SQL Server Profiler中的死锁图显示相同群集密钥上的相互锁定

Art*_*dod 4 sql-server indexing deadlock sql-server-profiler

我试图使用SQL Server Profiler确定死锁的原因.这是死锁图: 死锁图 这两个语句都是插入,后面跟着select scope_identity(); 实际上有两个并发进程,它们在一个循环中重复执行insert-select_identity.

我期望插入聚簇索引进行独占锁定,并且select获取非聚集索引的共享锁,然后它们等待彼此释放它们各自的indeces.

我看到的是两个进程都在等待释放相同的资源 - 聚集索引.怎么会这样?特定的追索权应属于一个过程或另一个过程.我在这里想念什么?感谢所有提前.

编辑:是的,隔离级别是Serializible.PS:可能,我对非聚集索引的共享锁的假设是错误的,只要我的select不包含where语句

Edit2:这是xml的一部分:

 <resource-list>
   <keylock hobtid="72057594148028416" dbid="29" objectname="<confidential>" indexname="PK_WP_Inbound_StockTransactionLine" id="lock9641700" mode="RangeS-S" associatedObjectId="72057594148028416">
    <owner-list>
     <owner id="process8e09288" mode="RangeS-S"/>
    </owner-list>
    <waiter-list>
     <waiter id="process991ce08" mode="RangeI-N" requestType="convert"/>
    </waiter-list>
   </keylock>
   <keylock hobtid="72057594148028416" dbid="29" objectname="<confidential>" indexname="PK_WP_Inbound_StockTransactionLine" id="lock9641700" mode="RangeS-S" associatedObjectId="72057594148028416">
    <owner-list>
     <owner id="process991ce08" mode="RangeS-S"/>
    </owner-list>
    <waiter-list>
     <waiter id="process8e09288" mode="RangeI-N" requestType="convert"/>
    </waiter-list>
   </keylock>
  </resource-list>
Run Code Online (Sandbox Code Playgroud)

根据这个,我认为它是由SERIALIZABLE隔离引起的范围扫描(谷歌搜索).但是,我仍然不明白这是怎么发生的,建议的补救措施是什么.

Ank*_*ush 5

考虑从访问相同记录的两个并行事务(T1和T2)调用以下代码.

Read LastRow
Insert AtLastRow
Run Code Online (Sandbox Code Playgroud)

让我们说上下文切换发生在Read.所以操作顺序是

T1 Read LastRow
T2 Read LastRow
T2 Insert AtLastRow // This will wait for T1 to finish.
T1 Insert AtLastRow // This will wait for T2 to finish. Hence deadlock!
Run Code Online (Sandbox Code Playgroud)

以上阅读将Range S-S锁定.最后插入也需要Range I-NRange S-S其他事务持有的现有锁不兼容.因此它等待.

可以有多种方法来解决此问题.

  1. 使用read committed作为整体隔离级别而不是可序列化.这样可以防止使用Range锁定.
  2. 使用更新锁(UPDLOCK)读取.这将在第一名采取独家更新锁定.因此,其他交易将在Read本身等待.
  3. 避免读取和插入/更新模式.只需直接进行插入/更新,让它失败.

如果您有任何疑问,请告诉我.