分析6锁和锁分区导致的死锁

  

官方文档中说到:

官方说明比较晦涩难懂,我尝试用一种易懂的方式说明SIX是什么。

关于锁有几个概念:粒度、层次结构和锁之间的兼容性。锁是用来锁定资源,而资源是包括很多种的,而这些不同的资源代表着不同的粒度。不同的资源间存在着层次结构,如表、分区、页、行、键等。锁的类型用很多种,粗略的分类包括共享锁(S)、更新锁(U)、排他锁(X)和架构锁(Sch)等,而不同类型的锁,有些是互斥的,有些是兼容的。如共享锁与其它类型的锁相互兼容,排他锁与其它的锁类型互斥。

SQL Server分配锁时,会沿着层次结构,从表级别开始分配锁,然后到最下层的行和键。在分配锁时,上级的资源会被分配意向锁(I),用来表示这个资源的下级某个资源已经被锁定了。意向锁也可以分为IS,IX,IU等类型。例如,更新表中某一行,需要在在行上分配X锁,而在行所属的数据页中分配意向锁IX,数据页所属的表上分配IX锁。

如果一个会话的事务当前持有了某个表或者数据页的S锁,而它接下来又要去修改表中的某一个行。这种情况下,事务需要获取行上的X锁和表或数据页上的IX锁,但是SQL Server只允许一个会话在一个资源上获取一个锁。也就是说没有办法在已经获得表或者页级别的S锁之后又分配IX给它。为了解决这个问题,于是就出现了两者的结合体:S+IX=SIX。 同理,如果先持有IX,再去获取S,也会得到SIX。

另外SQL Server中还有类似的锁类型UIX(U+IX),SIU(S+IU),机理也是一样的。这三种锁被称为转换锁。

 

首先不要把锁分区(Lock Partitioning)和分区锁(Partition Lock)搞混了。

官方文档:

获取已分区资源的锁时:

  • 只能获取单个分区的 NL、SCH-S、IS、IU 和 IX 锁模式

  • 对于以分区 ID 0 开始并且按照分区 ID排列的所有分区,必须获取非 NL、SCH-S、IS、IU 和 IX 模式的共享锁 (S)、排他锁 (X) 和其他锁。已分区资源的这些锁将比相同模式中未分区资源的锁占用更多的内存,因为每个分区都是一个有效的单独锁。内存的增加由分区数决定。Windows 性能监视器中 SQL Server 锁计数器将显示已分区和未分区锁所使用内存信息。

启动一个事务时,它将被分配给一个分区。对于此事务,可以分区的所有锁请求都使用分配给该事务的分区。按照此方法,不同事务对相同对象的锁资源的访问被分布到不同的分区中。

通过一个示例观察一下SIX和锁分区:

create  table t2 (    id int identity(1,1) ,     col1 int,     col2 int     )     
  go ,,,,
  insert  into  t2 ,,,, values (地板(rand() * 100),地板(rand () * 100)),,,,,
  go  20
  set  transaction  isolation  level  serializable ,,,
  begin  tran ,,,,
  insert  into  t2 ,,,, values (地板(rand() * 100),地板(rand () * 100)),,,,,
  select  id 得到t2 ,,,, where  @@ROWCOUNT> 0,以及id=SCOPE_IDENTITY (),,,,,
  SELECT  resource_type, request_mode, resource_description, resource_lock_partition ,,,,
  得到,,sys.dm_tran_locks ,,,,
  WHERE , resource_type  & lt;祝辞,“数据库”,以及request_session_id=@@SPID ,,,,
  回滚

分析6锁和锁分区导致的死锁

这个实例有24颗CPU,所以通过resource_lock_partition看到分区编号最到23了。因为六模式要获取所有锁分区,所以看到所有分区上都有六。

从图中可以<强>看出同一个事务中,不同的锁资源可以使用不同的锁分区

,

最近在做性能审查时发现某些实例的循环缓冲区中记录了一些死锁,其中一个如下:

分析6锁和锁分区导致的死锁

会话113持有了对象上的第九,需要再申请6。说明它修改数据后要去查询数。

会话79持有了对象上的六个,需要再申请6。这个就有点奇怪了,需要再仔细看看xml格式的死锁信息。

& lt; deadlock>,   ,,,& lt; victim-list>,   ,,,,,,,& lt; victimProcess    id=" process8809b88 "/祝辞,   ,,,& lt;/victim-list>,   ,,,& lt; process-list>,   ,,,,,,,& lt; process  id=皃rocess8809b88”,   taskpriority=" 0 ", logused=" 6844 ", waitresource=倍韵?,6:1541580530:10 ”,   waittime=" 967 ", ownerId=?638862771”, transactionname=皍ser_transaction”,   lasttranstarted=" 2016 - 06 - 06 t16:45:14.617”, xd=" 0 x8001d050”, lockMode=傲?   schedulerid=" 1 ", kpid=" 41740 ",状态=霸萃!?spid=" 113 ", sbid=?”, ecid=" 0 ",   优先级=" 0 ",trancount=?”, lastbatchstarted=?016 - 06 - 06 t16:45:14.627”,   lastbatchcompleted=" 2016 - 06 - 06 t16:45:14.627”, clientapp=" .Net  SqlClient  Data    提供者”,主机名=皒xxx”, hostpid=" 12552 ", loginname=" xxx ",   isolationlevel=" serializable  (4)“, xactid=?638862771”, currentdb=?”,   lockTimeout=" 4294967295 ", clientoption1=?71088672”, clientoption2=" 128056 "祝辞,   ,,,,,,,,,,,& lt; executionStack>,   ,,,,,,,,,,,,,,,& lt; frame  procname=" ",   行=" 3 ",stmtstart=" 220 ",   sqlhandle=" 0 x0200000072705a08155b23d8949f622375a2f263ba0d9099 "祝辞& lt;/frame>,   ,,,,,,,,,,,& lt; frame  procname=" ",行=?”,   sqlhandle=" 0 x000000000000000000000000000000000000000000000000 "祝辞& lt;/frame>,   ,,,& lt;/executionStack>,   ,,,& lt; inputbuf>,   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null

分析6锁和锁分区导致的死锁