阻塞与死锁 之二 锁资源模式和兼容性

SQL Server数据库引擎具有多粒度锁定,允许一个事务锁定不同类型的资源。为了尽量减少锁定的开销,数据库引擎自动将资源锁定在适合任务的级别。锁定在较小的粒度(例如行上)可以提高并发度,但开销较高,因为如果锁定了许多行,就需要维护很多锁。锁定在较大的粒度(例如表)上,会降低并发度,因为锁定整个表限制了其他事务对表中任意部分的访问,但其开销较低,因为需要维护的锁数目较少。

数据库引擎通常必须获取多粒度级别上的锁,才能完整地保护资源。例如,为了完整地保护对某一数据行的读取,数据库引擎实例不但需要获取行上的共享锁,还要辅以页和表上的意向共享锁。否则,如果同时有人对这个行所在的页面或表做了改动,也会妨碍事务的正常隔离。

表14-1列出了数据库引擎可以锁定的资源。

14-1 数据库引擎可以锁定的资源

资  源

说  明

 RID

 用于锁定堆(Heap)中的某一行

 KEY

 用于锁定索引上的某一行,或者某个索引键

 PAGE

 锁定数据库中的一个8 KB页,例如数据页或索引页

 EXTENT

 一组连续的8

 HoBT

  用于锁定表下面的某一个分区(partition)

 TABLE

 锁定包括所有数据和索引的整个表

 FILE

 数据库文件

 APPLICATION

 应用程序专用的资源

 METADATA

 元数据锁

 ALLOCATION_UNIT

 分配单元

 DATABASE

 整个数据库

在此基础上,SQLServer使用不同的锁模式锁定资源,这些锁模式确定了并发事务访问资源的方式。

表14-2显示了数据库引擎使用的资源锁模式。

14-2 数据库引擎使用的资源锁模式

锁 模 式

说  明

 共享(S

 用于不更改或不更新数据的读取操作,如 SELECT 语句

 更新(U

 用于可更新的资源中。防止当多个会话在读取、锁定以及随后可能进行的资源更新时发生常见形式的死锁

 排他(X

 用于数据修改操作,例如INSERTUPDATEDELETE。确保不会同时对同一资源进行多重更新

 意向

 放置在资源层次结构的一个级别上的锁,以保护较低级别资源上的共享或排他锁。如在对表内某页实施排他锁之前,先在该表上放置意向锁。如果第二个事务试图在该表级别上应用共享锁,则受到阻塞。第二个事务不必检查表内各个页锁,只需要检查表上的意向锁即可,以提升性能。意向锁包含三种类型:意向共享(IS),意向排他(IX)和意向排他共享(SIX

 架构

 在执行依赖于表架构的操作时使用。架构锁包含两种类型:架构修改(Sch-M)和架构稳定性(Sch-S

 大容量更新(BU

 在向表进行大容量数据复制且指定了 TABLOCK 提示时使用

 键范围

 当使用可序列化事务隔离级别时保护查询读取的行的范围。确保再次运行查询时其他事务无法插入符合可序列化事务的查询的行

                共享锁

共享锁(S锁)允许并发事务在封闭式并发控制下读取(SELECT)资源。资源上存在共享锁(S锁)时,任何其他事务都不能修改数据。

更新锁

在可重复读或可序列化事务中,一个修改需要先读取数据[获取资源(页或行)的共享锁(S锁)],然后修改数据[此操作要求锁转换为排他锁(X锁)]。如果两个事务获得了同一个资源上的共享模式锁,然后试图同时更新数据,则事务会把共享锁转换为排他锁(X锁)。由于两个事务都要转换为排他锁(X锁),并且每个事务都须等待另一个事务释放共享锁之后才能得到排他锁,以至于两个事务都无法完成转换,因此发生死锁。

为了避免这种潜在的死锁问题,SQLServer使用更新锁(U锁)。一次只有一个事务可以获得资源的更新锁(U锁)。事务真正修改数据时,将更新锁(U锁)转换为排他锁(X锁)。

排他锁

排他锁(X锁)可以防止并发事务对资源进行访问。使用排他锁(X锁)时,任何其他事务都无法读取或者修改数据;仅在使用NOLOCK提示或未提交读隔离级别时才会进行读取操作。

数据修改语句(如INSERT、UPDATE和DELETE)合并了读取和修改操作。语句在执行所需的修改操作之前,需要先执行读取操作以获取数据。因此,数据修改语句通常会先请求共享锁和排他锁。例如,UPDATE语句可能根据与一个表的联接修改另一个表中的行。在此情况下,除了请求更新行上的排他锁之外,UPDATE语句还将请求在联接表中读取的行上的共享锁。

意向锁

数据库引擎使用意向锁来保护锁层次结构的底层资源,以防止其他事务对自己锁住的资源造成伤害,提高锁冲突检测性能。

例如,当读取表里的页面时,在请求页共享锁(S锁)之前,事务在表级请求共享意向锁。这样可以防止其他事务随后在表上获取排他锁(X锁),修改整个表格。意向锁可以提高性能,因为数据库引擎仅在表级检查意向锁,确定事务是否能安全地获取该表上的锁,而不需要检查表中的每行或每页上的锁以确定事务是否可以锁定整个表。

架构锁

数据库引擎在表数据定义语言(DDL)操作(例如添加列或删除表)的过程中使用架构修改(Sch-M)锁,阻止其他用户对这个表格的访问。

数据库引擎在编译和执行查询时使用架构稳定性(Sch-S)锁。Sch-S锁不会阻止其他事务访问表格里的数据。但是,会阻止对表格做修改性的DDL操作和DML操作。

大容量更新锁

数据库引擎在将数据大容量复制到表中时使用大容量更新(BU)锁,并指定TABLOCK提示或使用sp_tableoption设置table lock on bulk load表选项。大容量更新锁(BU锁)允许多个线程将数据并发地大容量加载到同一表,同时防止其他不进行大容量加载数据的进程访问该表。

键范围锁

在使用可序列化(SERIALIZABLE)事务隔离级别时,对于Transact-SQL语句读取的记录集,键范围锁可以隐式保护该记录集中包含的行范围。键范围锁可防止幻读。通过保护行之间键的范围,它还可防止对事务访问的记录集进行幻插入或删除。

锁兼容性控制多个事务能否同时获取同一资源上的锁。如果资源已被另一事务锁定,则仅当请求锁的模式与现有锁的模式相兼容时,才会授予新的锁请求。如果请求锁的模式与现有锁的模式不兼容,则请求新锁的事务将被迫进入等待状态,阻塞也就随之产生。例如,如果一个事务申请了在某个资源上的排他锁(X锁),则在它释放排他锁(X锁)之前,其他事务均无法获取该资源的任何类型(共享、更新或排他)的锁。另一种情况是,如果一个事务已经获得了某个资源上的共享锁(S锁),则即使第一个事务尚未完成,其他事务也可以获取该项的共享锁或更新锁(U锁)。但是,在第一个事务释放共享锁之前,其他事务无法获取排他锁。

表14-3显示了最常见的锁模式的兼容性。

14-3 最常见的锁模式兼容性

 

现有授予模式

请求模式

IS

S

U

IX

SIX

X

意向共享(IS)

共享(S)

更新(U)

意向排他(IX)

意向排他共享(SIX)

排他(X)

锁的模式和兼容性是SQLServer预先定义好的,没有任何参数或配置能够去修改它们。所以要做什么事情,SQL Server就会去申请什么类型的锁。出现了某种类型的锁,它就会带来预期的兼容性,也就是所谓的事务隔离行为。但是申请锁的粒度,是数据库设计能够影响的。如果应用申请的锁粒度都比较小,产生阻塞的几率就会比较小。如果一个连接会经常申请页面级、表级,甚至是数据库一级的锁资源,程序产生阻塞的可能性就会很大。

同时,应用程序可以决定一个连接什么时候释放它申请到的锁。如果一个连接总是能够非常快地把申请到的锁释放掉,那阻塞就不容易发生。如果它总是长时间地持有某些锁资源,那么就很容易发生阻塞了

什么行为会影响锁的粒度,以及持有锁的时间长短呢?这个当然和应用定义的事务性质有关系。

1. 一个事务内部要访问或者修改的数据量越大,它所要申请的锁的数目就会越多,粒度也就可能越大。

例如一个事务如果要修改一张表里的大部分数据,那在它提交以前,可能其他的用户都无法去访问这张表里的记录。而如果这个事务只对一两条记录进行修改,那么大部分的用户访问可能不会受到影响。

2. 一个事务做的事情越复杂,它要申请的锁的范围也就会越大。

如果一个事务做的修改只在一个表上,那它只会申请这张表上的锁。访问其他表的用户就不会受到影响。如果一个事务先后对许多张表做了修改,那访问到这些表的用户就都会被影响到。

3. 一个事务延续的时间越长,它持有的锁的时间也会越长。

很多锁是要在事务提交的时候才会被释放的。如果事务能够很快结束,它申请的锁就不会延续很久,也就不容易阻塞住别人。如果这个事务里有很多语句,或者是某句语句要运行很久,或者是语句都结束了,但是连接没有及时提交事务,那有些锁就会一直被这个连接所持有,别人就会很容易被它给阻塞住。

上面的因素都是比较浅显的,但是和应用逻辑紧密相关。对于一个固定的应用逻辑,这些因素能够调整的余地可能不是很大。为了缓解阻塞问题,还有什么其他因素会影响锁的粒度,以及持有锁的时间长短呢?有两大因素非常关键:事务的隔离级别能影响锁的申请以及释放的时间;而语句的执行计划,也会影响到锁的粒度以及申请的数量。所以对于相同的逻辑,如果开发者选择合适的事务隔离级别,引导语句使用优化的执行计划,很多时候也能达到缓解阻塞的目的。下面两节将对它们做详细探讨。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值