2012-09-25 39 views
4

我想使用SQL Server事件探查器来识别死锁的原因。 这里的僵局图: Deadlock graph 两个陈述都是插入其次是select scope_identity(); 其实一个有2个并发流程,反复做嵌入select_identity在一个周期。SQL服务器事件探查器中的死锁图显示相同的集群密钥上的相互锁

我希望那是什么插入采取排它锁在聚集索引选择采取非聚集索引的共享锁,然后他们等待对方释放它们各自的的indeces。

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

编辑:是的,隔离级别是Serializible。 PS:也许,我的关于非聚集索引的共享锁的假设是错误的,只要我的选择不包含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隔离(谷歌搜索引擎)。但是,我不明白这是怎么发生的,建议的补救措施是什么。

+0

你正在使用什么隔离级别?序列化?如果是这样的原因? –

+0

是的,我忘了说,对不起。我编辑了帖子 –

+0

发布死锁XML,而不是图像。图像不完整,误导而且往往是错误的。 –

回答

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)。这将独家更新 锁定在第一位。因此其他交易将在阅读本身等待。
  3. 避免读取和插入/更新模式。直接插入/更新 ,让它失败。

让我知道如果您有任何问题。

+0

3.避免读取和插入/更新模式。那我该如何处理失败?即。如果记录已经存在,我需要做别的事情(比如说,显示一个特定的消息)。我应该只是w8例外吗?然后什么?解析异常数据以确定其确切原因?另外,为什么要插入/更新失败?考虑一种情况,我需要检查业务逻辑约束,而不是数据模型约束。可能的解决方案也是将读操作移出事务处理。但在我们的情况下,这是2%的重构,所以我将改变隔离级别作为解决方法。谢谢=) –

+0

@ArturUdod让你说读一行key = 10并增加值。您可以读取该值并更新它,或者继续并更新。如果密钥不存在,则上述更新将失败。现在,如果您检测到失败,则将值为1的键10插入。这有帮助吗? – Ankush

+0

是的,我明白了。但是,正如我所说:让我们假设我只想增加一个值,如果它小于100.如果它已经是100,那么我想显示一条消息。关闭源,可以有一个“检查”约束,但这是一个简单的例子。我可能有更复杂的验证业务逻辑,我实际上需要在修改数据之前执行读取操作。 –