SQL Server Deadlock - Two SELECT Exclusive Locks on Exact Same Index and Key

最近做性能優化時碰到下面的死鎖問題,起初看到這個圖感覺很詭異,無法理解,兩個查詢語句爲啥會導致死鎖呢?查詢語句爲啥會導致X(排他)鎖的產生呢?最後在查閱了一部分資料之後,終於可以解釋通了。 

 
1. 首先,此圖中兩個Key Lock分別代表數據庫表上的兩個行各自的行鎖,是兩個鎖,而不是一個鎖。圖中的兩個事務執行的是相同的代碼,在事務中,首先做了一個查詢,最後對查詢的數據進行了更新。因此,就可以理解圖中X(排他)鎖是因爲事務中的更新語句導致的,而不是查詢語句導致的(雖然右鍵兩個事務顯示的都是相同的查詢語句)。

所以,此圖的意思是事務762385持有下面方框對應的行X(排他)鎖,正在申請上面方框對應的行S(共享)鎖。而事務762460持有上面方框對應的行X(排他)鎖,正在申請下面方框對應的行S(共享)鎖。而X鎖和S鎖是不能同時獲得的,因此就發生了等待死鎖。

 

2. 再來看看查詢語句爲啥會導致申請S(共享)鎖失敗,查詢語句的執行計劃如下:可以看到查詢語句使用主鍵生成的Clustered索引進行了全表掃描,因此它會導致與更新無關的行在掃描的過程當中也需要申請S(共享鎖)。


 

3. 如何只申請需要更新行的S(共享)鎖呢?因爲我們的查詢語句對應的的兩個查詢條件正好對應有一個索引,所以只需要修改查詢語句,使得查詢計劃使用這個存在的索引,這樣就可以達到目的了。但是這樣會引入部分需要的字段無法在同一個查詢語句中查出來。解決辦法是,先通過這個修改的查詢語句找到該行的主鍵,然後再通過主鍵找到整行,因爲主鍵也不是進行全表掃描,只會申請更新行的S(共享)鎖。執行計劃如下:


 

4. 還有一種辦法是將事務分爲兩個小的事務,一部分做查詢,一部分做更新。這樣就不會出現同一個事務既需要X(排他)鎖,又需要S(共享)鎖的情況,也可以避免死鎖的發生。或者將此部分的邏輯進行順序化,也可以避免死鎖。

 

參考文檔:

1. SQL Server Deadlock - Two SELECT Exclusive Locks on Exact Same Index and Key [closed]

此文遇到了類似的問題,但是無解。問題描述相對比較準確。

 

2. Locking in Microsoft SQL Server (Part 3 – Blocking in the system)

此文詳細描述了持有X(排他)鎖,申請S(共享鎖)導致死鎖的情況,和我們遇到的問題一致。

 

3. SQL Server上的一個奇怪的Deadlock及其分析方法

此文描述了類似的死鎖問題,對於原因講述的比較詳盡,操作方法執行比較困難。因爲如果打出所有的SQL Trace,會產生數百萬條的記錄,如何在這些記錄當中找出死鎖對應的兩個事務對應的SQL Trace還是相當有困難的。可以考慮將生成的SQL Trace導入到一張數據庫表中,在導入的過程當中每隔5分鐘刪除所有我們不需要的事務對應的SQL Trace。這樣最終得到的SQL Trace會減少到不到一萬行。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章