前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SQL SERVER 锁升级的 investigation 与 别吃黄连

SQL SERVER 锁升级的 investigation 与 别吃黄连

作者头像
AustinDatabases
发布2019-09-04 11:26:00
7420
发布2019-09-04 11:26:00
举报
文章被收录于专栏:AustinDatabasesAustinDatabases

前些日子在分析SQL SERVER 死锁的过程中,检查有一些莫名其妙的死锁,两个根本不搭噶的事务,锁在了一起,WHY,其实SQL SERVER 在数据库界,算是一朵奇葩,独有的锁升级的技术,我想你应该不曾听到 MYSQL ,ORACLE , PG ,MONGODB 这些数据库提及到的锁升级的问题。

而牵扯到锁升级到额问题,就需要提及,到底为什么锁升级,锁从哪里升级到哪里的问题。所以就有了这篇文字,关于锁升级的东西。

首先我们在谈论锁的时候,的先站在一个讨论的起跑线,就是锁是发生在内存级别的,并且锁的开始和结束都是伴随着“事务”的开始和结束。在达成如上的共识后我们就开始下面的一些讨论和研究。

当事务管理器接收到提交请求时,它向事务中涉及的所有资源管理器发送一个prepare命令。然后,每个资源管理器执行使事务持久所需的所有操作,并将保存事务日志映像的所有缓冲区刷新到磁盘。当每个资源管理器完成准备阶段时,它将准备的成功或失败返回给事务管理器。

如果事务管理器从所有资源管理器接收到成功的准备,它将向每个资源管理器发送提交命令。然后,资源管理器可以完成提交。如果所有资源管理器都报告提交成功,那么事务管理器将向应用程序发送成功通知。如果任何资源管理器报告准备失败,事务管理器将向每个资源管理器发送回滚命令,并指示向应用程序提交失败。

SQL SERVER 在什么时候会选择什么样的锁的因素可能有哪些

下面是部分SQL SERVER 中可以进行锁的资源样本

RID

没有建立聚簇索引(HEAP TABLE)中标识行 ROW ID

KEY

索引中的行锁,用于在可序列化事务中保护键范围

PAGE

8KB的page 页,作为一个锁定的单位

EXTENT

连续的8 个页面,作为锁定的单位

HoBT

堆或b树。保护表中没有聚集索引的b树(索引)或堆数据页的锁。

TABLE

问题:为什么要这么多锁的类型,MYSQL innodb 不仅仅有 row lock吗?

作为一个商业数据库,在设计之初SQL SERVER 考虑了下面一个图(假设),使用低级锁(如行锁)可以降低两个事务同时请求同一数据块上的锁的概率,从而提高并发性,但使用低级锁还会增加锁的数量和管理锁所需的资源反之使用表或页锁可以降低开销,但代价是降低并发性。

SQL Server数据库引擎使用动态锁定策略来确定最经济有效的锁。数据库引擎会根据模式和查询的特性自动确定在执行查询时哪些锁是最合适的。例如,为了减少锁定的开销,优化器可以在执行索引扫描时选择索引中的页级锁定。这样做的好处也是显而易见,如果我有多行在一个PAGE中,并且都需要更改,系统会根据需要索引的资源来锁定这个PAGE,而不是一个页面里面的每个行,因为要考虑每个锁的管理,申请,释放,都是需要相关CPU 资源,内存资源的,如果能在不影响并发度的情况下,锁的粒度有效控制是有助于系统的信息的访问和修改的。

并且SQL SERVER 也是可以在表的创建,或使用中进行锁释放可以自动进行升级的设置的,你可以打开表的锁升级,或禁止掉他。

说到这里不得不说说SQL SERVER 锁的历史 SQL SERVER 7.0 之前的时候,(应该不是我出生的时候,在很久很久很久久以前久以前),SQL SERVER 是不支持 ROW 锁的,而仅仅支持 PAGE LOCK,并且一个页面是 2KB ,在 SQL SERVER 7.0,他们将SQL SERVER 变为了 8KB 的PAGE ,并且开始支持了 ROW LOCK。那到底为什么 SQL SERVER 不能做成和MYSQL 一样,仅仅支持行锁就好的数据库,为什么单库的商业数据库还是有优势的(注意这是问句)

下面是一个行锁的结构

锁是一个64或128字节的内存结构(分别用于32位或64位机器),每个持有或请求锁的进程都有另外32或64字节。如果您需要对每一行都使用锁,并且扫描一百万行,那么您需要超过64MB的RAM来保存该进程的锁。

一个语句在一个对象上持有的锁的数量超过了一个阈值。举例目前这个阈值是5000个锁,超过就会触发esclation,如果锁分布在同一语句中的多个对象上,则不会发生锁升级——例如,一个索引中的3000个锁和另一个索引中的3000个锁,另一方面锁资源占用的内存超过启用内存的40%,那么锁会将发生升级。

那锁升级到底是好不好,回答是 呵呵, 我想你明白我的意思。为什么

当触发锁升级时,如果存在冲突锁,则会先增加更多的X锁(我想你应该是懂这个过程的),并且不同进程持有的同一表或分区上有并发的X锁,则锁升级尝试将失败。每次事务在同一对象上获得另外更多个锁时,SQL Server都会继续尝试升级锁,成功后会将SQL Server索引或堆表上的所有行锁进行释放。

可以想想这个锁升级从上到下的描述中,触发他的伴随的是大事务,占用更多的内存,系统陷入了可能繁忙的状态,那此时进行锁升级,可能会成功,可能会失败,同时成功后,锁的级别将从ROW 变成 PAGE 或者更宽泛的锁,系统将由 SHARE 变为 ONLY You use it . 其他的事务如果访问你的资源,你是不是就不在管他们死活。

这还不是最糟糕的,锁升级会导致更多的死锁的出现,并且是莫名其妙的,看似两个根本就无关的事务,也会锁在一起,我想这时候如果你的领导来询问你的时候为什么这么多莫名其妙的死锁时,你是不是已经可以,有理有据来和他 make clear 一下了。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-09-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 AustinDatabases 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档