Sql-Server-2008

為什麼這個查詢會導致死鎖?

  • May 8, 2020

為什麼這個查詢會導致死鎖?

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提供的文章,其中包含如何避免此類死鎖的解決方案:

  • 從讀者的投影中消除不必要的列,這樣他就不必查找聚集索引
  • 將所需列作為包含列添加到非聚集索引以使索引覆蓋,再次使讀者無需查找聚集索引
  • 避免必須維護非聚集索引的更新

在我看來,好像您正試圖在同一個語句中並在同一個表上執行 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

引用自:https://dba.stackexchange.com/questions/2063