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

时间:2012-09-25 08:19:35

标签: sql-server indexing deadlock sql-server-profiler

我正在尝试使用SQL Server Profiler确定死锁的原因。 这是死锁图: Deadlock graph 这两个陈述都是插入,后跟select scope_identity(); 实际上有2个并发进程在循环中重复执行 insert-select_identity

我期望 insert 聚集索引进行独占锁定,而 select 采用非共享锁定 - 聚集索引,然后他们等待彼此释放各自的权力。

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

编辑:是的,隔离级别是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>

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

1 个答案:

答案 0 :(得分:5)

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

Read LastRow
Insert AtLastRow

让我们说上下文切换发生在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!

以上阅读将Range S-S锁定。最后插入还需要Range I-N,这与其他事务持有的现有Range S-S锁不兼容。因此它等待。

有多种方法可以解决这个问题。

  1. 使用读取已提交作为整体隔离级别,而不是可序列化的。 这样可以防止进行范围锁定。
  2. 使用更新锁定(UPDLOCK)进行阅读。这将采取独家更新 锁定第一名。因此,其他交易将在Read本身等待。
  3. 避免使用读取和插入/更新模式。直接前进吧 插入/更新,让它失败。
  4. 如果您有任何问题,请与我们联系。