Sql 更新到独占锁转换

Sql 更新到独占锁转换,sql,sql-server,sql-server-2008-r2,locking,Sql,Sql Server,Sql Server 2008 R2,Locking,SQL Server 2008R2-ReadCommitted隔离级别 我正在尝试计算SQL server何时将更新锁转换为独占锁。例如,我有表dbo.TableA。dbo.TableA有两列PKCol1和NCCol2。PKCol1是聚集索引,NCCol2上有一个非聚集索引。如果我要执行 BEGIN TRAN DELETE FROM dbo.TableA WHERE NCCol2 = 1 COMMIT TRANSACTION 优化者选择扫描NCCol2以查找所有候选记录,而非聚集索

SQL Server 2008R2-ReadCommitted隔离级别

我正在尝试计算SQL server何时将更新锁转换为独占锁。例如,我有表dbo.TableA。dbo.TableA有两列PKCol1和NCCol2。PKCol1是聚集索引,NCCol2上有一个非聚集索引。如果我要执行

BEGIN TRAN  

DELETE
FROM dbo.TableA 
WHERE NCCol2 = 1

COMMIT TRANSACTION 
优化者选择扫描NCCol2以查找所有候选记录,而非聚集索引操作符则扫描索引中的所有记录。向每个候选记录添加更新锁,直到扫描完整个索引,然后聚集索引删除操作符将这些锁转换为独占锁并删除

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

基本上,哪一个操作符将更新锁转换为独占锁,即在扫描确定记录是匹配项后进行非聚集索引扫描,或者在确定候选行并将其传递给它后进行聚集索引删除

网上书籍告诉我

更新(U)

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

独家(X)

用于数据修改操作,如插入、更新或删除。确保不能同时对同一资源进行多个更新

附加信息1

我实际上是在调查一个死锁,它发生在下面的非唯一非聚集INT Index2上,在优化者选择了以下计划之后

僵局被解释为

  • 受害者在dbo.Table1 Index2行1上获得了更新锁
  • 所有者对dbo.Table1 Index2 row2进行了独占锁定
  • 受害者等待dbo.Table1 Index2第2行上的更新锁
  • 所有者等待dbo.Table1 Index2 row1上的更新锁
  • 我的理解是,执行计划中的每个操作符都是按照从右到左、从上到下的顺序完整执行的。但我的理解是,更新锁仅在更新/插入或删除期间转换为独占锁,即聚集索引删除运算符。因此,我不确定为什么步骤2中的所有者在Index2 row2上有一个排他锁,这表明它处于聚集索引删除步骤,但仍在等待更新锁,这将表明它也是非聚集索引扫描步骤。这两个步骤怎么可能同时进行

    但是,如果您认为更新锁和排他锁都是在索引扫描期间使用的,那么这种死锁将更有意义

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

    @Bogdan Sahlan和brian-非常感谢您的帮助和建议。

    上下文:

    -DELETE语句的目标表具有唯一聚集索引(PK)和非聚集索引

    -聚集索引的键是
    IDA

    -非聚集索引的键是
    NCCol2

    -
    表A
    内容:

    -- 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)
    
    在这方面:

  • SQL Server将选择一个
    Index Seek
    (在非聚集索引上,使用
    NCCol2
    键)查找记录,并选择一个运算符删除记录:

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

  • 对于非聚集索引中的每一条记录,取一个
    U
    锁(参见lockhash
    (8194443284a0)
    ),并对聚集索引中的相应记录取另一个
    U
    锁(PK;参见lockhash
    (29cf3326f583)

  • 然后,聚集索引记录上先前的
    U
    锁(lockhash
    (29cf3326f583)
    )被转换为
    X
    锁,非聚集索引记录上的
    U
    锁(lockhash
    (8194443284a0)
    )也被转换为
    X

  • 两个索引中的记录都被删除(我认为现在是删除这些记录的时候),并且先前的
    X
    锁被释放

  • 使用非聚集索引查找另一行>转至步骤2

  • 您可以使用SQL事件探查器(或服务器跟踪、扩展事件)截获这些事件(
    Lock:Aquired
    Lock:Released
    ):

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

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

    1) 一些(正如brian指出的)由类型优先级生成的(
    1
    将是
    TINYINT
    ,如果数据库配置为
    简单参数化
    ,或者
    1
    将具有与列类型相同的类型,如果数据库配置为
    强制参数化

    2) 可以禁用索引

    3) 它是一个过滤索引(),或者是在计算列上定义的索引,设置()不合适

    4) 这是一个经过过滤的索引,数据库已激活
    参数化强制设置


    5) [低概率]这是一个小表,(出于某种原因)SQL Server为@Bogdan的内部结构选择了
    扫描
    而不是
    搜索

    +1。只要NCCol2与它所比较的相等值的类型相同,这一点就成立。例如,如果NCCol2是varchar(25),并且相等值是int,那么它将是一个nc扫描,因为数据类型优先级要求varchar端在比较之前获得到int的隐式转换。如果你没有考虑到这一点