2

SQL Server 2008R2 - ReadCommitted 隔离级别

我正在尝试准确计算 SQL 服务器何时将更新锁转换为独占锁。例如,我有表 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 上发生的死锁

非聚集索引扫描 死锁翻译为

  1. 受害者在 dbo.Table1 Index2 row1 上获取了更新锁
  2. 所有者对 dbo.Table1 Index2 row2 进行了排他锁
  3. 受害者等待 dbo.Table1 Index2 row2 上的更新锁
  4. 所有者等待 dbo.Table1 Index2 row1 上的更新锁

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

但是,如果您认为在索引扫描期间同时使用了更新锁和排他锁,那么这种死锁会更有意义。

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

聚集索引删除 @Bogdan Sahlean 和 @brian - 非常感谢您的帮助和建议。

4

1 回答 1

2

语境:

- DELETE 语句的目标表有一个唯一的聚集索引(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)来查找记录,并选择一个聚集索引删除运算符来删除记录: 在此处输入图像描述

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

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

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

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

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

您可以使用 SQL Profiler(或服务器跟踪、扩展事件)拦截这些事件(Lock:AquiredLock:Released): 在此处输入图像描述

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

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

1) 由类型优先级生成的一些隐式转换(正如 brian 指出的那样)(如果数据库配置为,1则将是 a TINYINT,如果数据库配置为Simple Parametrization1则将具有与列类型相同的类型 Force Parametrization)。

2) 可以禁用索引。

3)它是过滤索引(链接)或者是在计算列上定义的索引,并且设置(链接:SET Option Requirements)不合适。

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

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

于 2013-08-01T19:59:30.550 回答