更新为独占锁定转换

时间:2013-08-01 18:57:38

标签: sql sql-server sql-server-2008-r2 locking

SQL Server 2008R2 - ReadCommitted Isolation Level

我正在努力确定SQL服务器何时将更新锁转换为Exclusive锁。例如,我有表dbo.TableA。 dbo.TableA有两个列PKCol1和NCCol2。 PKCol1是一个聚簇索引,NCCol2上有一个非聚集索引。如果我要执行

BEGIN TRAN  

DELETE
FROM dbo.TableA 
WHERE NCCol2 = 1

COMMIT TRANSACTION 

优化器选择扫描NCCol2以查找所有候选记录,非聚集索引操作符是否会扫描索引中的所有记录。在聚簇索引删除操作符然后将这些锁转换为独占锁并删除之前,在每个候选记录扫描整个索引之前添加更新锁。

或者非聚集索引运算符是否会依次扫描每个记录向候选记录添加更新锁,评估该行是否匹配以及是否将更新锁转换为独占锁。

基本上哪个运算符将更新锁转换为独占锁,一旦扫描识别出记录匹配或聚集索引删除,一旦候选行被识别并传递给它,非聚集索引扫描?

在线图书告诉我

更新(U)

用于可以更新的资​​源。防止在多个会话正在读取,锁定以及稍后可能更新资源时发生的常见形式的死锁

独家(X)

用于数据修改操作,例如INSERT,UPDATE或DELETE。确保无法同时对同一资源进行多次更新。

其他信息1

我正在调查优化器选择以下计划后在非唯一非群集INT Index2上发生的死锁

Non-Clustered Index Scan 死锁转换为

  1. 受害者对dbo.Table1 Index2 row1
  2. 进行了更新锁定
  3. 所有者对dbo.Table1 Index2 row2
  4. 进行了一次eXclusive锁定
  5. 受害者在dbo上等待更新锁定.Table1 Index2 row2
  6. 所有者等待dbo.Table1 Index2 row1
  7. 上的更新锁定

    据我了解,执行计划中的每个操作员都是按照从右到左从上到下的顺序执行的。但我的理解是,在UPDATE / INSERT或DELETE(即聚簇索引删除操作符)期间,更新锁仅转换为独占锁。因此,我不确定为什么第2步中的所有者对Index2 row2有一个独占锁定,这表明它是在聚集索引删除步骤,但仍在等待更新锁定,这将表明它也是非聚集索引扫描步骤。怎么可能同时在两个步骤?

    但是,如果您认为在索引扫描期间都进行了更新和排它锁,那么这种死锁会更有意义。

    重新编译后,优化器选择在没有问题的情况下寻找聚集索引

    Clustered Index Delete @Bogdan Sahlean& @brian - 非常感谢你的帮助和建议。

1 个答案:

答案 0 :(得分:2)

上下文:

- DELETE语句的目标表具有UNIQUE聚簇索引(PK)和非聚集索引。

- 群集索引的关键是IDA

- 非聚集索引的键是NCCol2

- TableA内容:

-- Clustered index (C index)
NCCol2 IDA lockhash (these values are the "identifier" of locks)
------ --- --------------
1      11  (29cf3326f583)
2      22  (31178495a25a)

-- Non-Clustered index (NC index)
NCCol2 lockhash
------ --------------
1      (8194443284a0)
2      (61a06abd401c)

在此背景下:

  1. SQL Server将选择Index Seek(在带有NCCol2密钥的非聚集索引上)来查找记录,并选择Clustered Index Delete运算符来删除记录: enter image description here

  2. Index Seek(在NCCol2上)运算符使用此谓词(NNCol2=1)查找记录,

  3. 对于来自非聚集索引的每条记录,都会执行U锁定(请参阅lockhash (8194443284a0)),并对聚集索引(PK)中的相应记录执行另一个U锁定;请参阅lockhash (29cf3326f583)),

  4. 然后,聚集索引记录的先前U锁定(lockhash (29cf3326f583))将转换为X锁定,并且U锁定非聚集索引记录(lockhash (8194443284a0))也被转换为X锁定。

  5. 删除两个索引中的记录(我认为这是删除这些记录的时刻)并释放先前的X锁。

  6. 使用非聚集索引>查找另一行转到步骤#2。

  7. 您可以使用SQL事件探查器(或服务器跟踪,扩展事件)拦截这些事件(Lock:AquiredLock:Released): enter image description here

    TLTR:索引搜索(查找记录)> U锁定NC索引记录> U锁定C索引记录> U - > X表示C索引记录> U - > X表示NC索引记录>删除记录>重复(找到另一行)。

    编辑1: Scan可能有很多原因:

    1)如果为1或{{1}配置数据库,则由类型优先级生成的implicit conversions(如brian所指出的)TINYINT将为Simple Parametrization如果为1配置了数据库,则将具有与列类型相同的类型。

    2)可以禁用索引。

    3)这是一个过滤的索引(link)或者是在计算列上定义的索引,而设置(link: SET Option Requirements)是不合适的。

    4)这是一个过滤的索引,该数据库已激活Force Parametrization设置。

    5)[低概率]这是一个小表,并且(由于某种原因)SQL Server选择Parametrization Forced而不是Scan