为什么此查询会导致死锁?


11

为什么此查询会导致死锁?

UPDATE TOP(1) system_Queue SET
  [StatusID] = 2,
  @ID = InternalID
WHERE InternalID IN (
    SELECT TOP 1 
      InternalID FROM system_Queue
    WHERE IsOutGoing = @IsOutGoing AND StatusID = 1
ORDER BY MessageID ASC, InternalID ASC)

添加了死锁图:

<keylock hobtid="72057594236436480" dbid="9" objectname="Z.dbo.system_Queue" indexname="PK_system_Queue" id="lock5b25cc80" mode="X" associatedObjectId="72057594236436480">
    <owner-list>
     <owner id="processc6fe40" mode="X"/>
    </owner-list>
    <waiter-list>
     <waiter id="processc7b8e8" mode="S" requestType="wait"/>
    </waiter-list>
   </keylock>
   <keylock hobtid="72057594405453824" dbid="9" objectname="Z.dbo.system_Queue" indexname="IX_system_Queue_DirectionByStatus" id="lock48cf3180" mode="S" associatedObjectId="72057594405453824">
    <owner-list>
     <owner id="processc7b8e8" mode="S"/>
    </owner-list>
    <waiter-list>
     <waiter id="processc6fe40" mode="X" requestType="wait"/>
    </waiter-list>
   </keylock>

添加:

感谢Sankar的文章,其中提供了如何避免这种死锁的解决方案:

  • 从读者的投影中消除不必要的列,因此他不必查找聚簇索引
  • 将所需的列作为包含的列添加到非聚集索引中以使索引覆盖,从而使读者不必查找聚集索引
  • 避免必须维护非聚集索引的更新

您使用哪个数据库平台的版本?默认的trx隔离(或并发)级别是多少?当前在system_Queue表上存在哪些索引?
SQLRockstar 2011年

添加了死锁图的@SQLRockstar部分,SQL Server 2008
garik 2011年

由IsOutGoing和StatusID提供的@SQLRockstar IX_system_Queue_DirectionByStatus索引。
garik 2011年

Answers:


13

在我看来,好像您正在尝试在同一条语句和同一张表中执行SELECT和UPDATE一样。

SELECT在IX_system_Queue_DirectionByStatus索引内的值上持有一个共享锁,而UPDATE需要释放这些锁才能获得它的独占锁,这将更新主键(我猜这是集群的,也是主键的一部分)。 IX_system_Queue_DirectionByStatus键值)。

无论如何,我的猜测是,只有在极少的机会下它选择和更新的索引值不会冲突,该查询才会成功。每次执行时它是否陷入僵局(我想是会的)。

这是一个详细解释死锁的链接:http : //sqlblog.com/blogs/jonathan_kehayias/archive/2008/07/30/the-anatomy-of-a-deadlock.aspx


答对了!谢谢。我见过的僵局实在是很奇怪的情况。谢谢你的答案。
garik 2011年

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.