Sql-Server
普通 IX 鎖死鎖
我試圖弄清僵局。有問題的表
mytb
僅用於以下查詢:
delete mytb with (uplock,holdlock) where key_value=@value
通過 sp_executesql 呼叫。後面提到的兩個程序都使用相同的程式碼,除了鍵值。
我正在使用跟踪標誌 1222,這是伺服器日誌中的資源列表部分:
resource-list objectlock lockPartition=0 objid=1433553235 subresource=FULL dbid=16 objectname=mydb.dbo.mytb id=lock5620a3480 mode=IX associatedObjectId=1433553235 owner-list owner id=process4bd94c8 mode=IX waiter-list waiter id=process4c85288 mode=X requestType=convert objectlock lockPartition=0 objid=1433553235 subresource=FULL dbid=16 objectname=mydb.dbo.mytb id=lock5620a3480 mode=IX associatedObjectId=1433553235 owner-list owner id=process4c85288 mode=IX waiter-list waiter id=process4bd94c8 mode=X requestType=convert
我的理解如下:兩個程序(讓我們從它們的最後兩個 id 字元中稱它們為“c8”和“88”)設法在表上獲得相同的 IX 鎖,然後嘗試變成 X 鎖以刪除必要的行,但一個程序阻塞了另一個程序。
我的理解正確嗎?如果是,為什麼程序共享 IX 鎖?系統是否不應該拒絕訪問 IX 鎖來限制競爭條件的程序,這將導致第一個程序首先完成,然後第二個程序可以開始?
發表評論補充:在探勘更多時,我發現
where
條件上的索引不存在,而我希望它是聚集的主鍵。沒有這個索引會不會是死鎖的原因?
沒有這個索引會不會是死鎖的原因?
是的。每個查詢都將從一個 IX 鎖開始,然後開始獲取鍵範圍上的 U 鎖。由於
holdlock
提示,它將使用範圍鎖定,否則它將是單個鍵上的正常 U 鎖定。但是在使用 (updlock,holdlock) 掃描數千行之後,每個都會嘗試將鎖升級到表級 X 鎖(對象鎖是分區的)
兩個會話都無法在表上獲得 X 鎖,因為另一個會話具有不兼容的 IX 鎖,因此死鎖。
使用選擇性索引,每個會話只需要讀取和鎖定少數鍵值,因此不會升級為表鎖定。