最近看了高兄的一篇文章,
Sql Server 高頻,高並發訪問中的鍵查找死鎖解析,很有收獲,里面講到了鍵查找引起的死鎖問題。
當然看的過程中,其實自己有個疑問:
對於鍵查找這類查詢,會申請哪些鎖,鎖申請和釋放的順序是怎樣的?
准備
備注:測試表仍然使用高兄文中創建的測試表testklup
在開始之前,使用dbcc ind 命令先看下測試表的數據組織情況

然后語句執行計划圖如下:

查看申請了哪些鎖
為了得到查詢會申請哪些鎖,通過如下這條查詢就可以得到
begin tran select cont2 from testklup with(HOLDLOCK) where nlskey=1
在默認的事務隔離級別下,開啟事務,然后查詢中使用HOLDLOCK提示。HOLDLOCK將共享鎖保留到事務完成,而不是在相應的表、行或數據頁不再需要時就立即釋放鎖。
然后使用DMV視圖sys.dm_tran_locks來查看持有鎖的情況,查詢結果如下:
從查詢結果,可以得出申請了如下的鎖:
1)在表object上申請了IS鎖
2)在非聚集索引PAGE上申請了IS鎖
3)在非聚集索引KEY上申請了S鎖
4)在聚集索引的PAGE上申請了IS鎖
5)在聚集索引的KEY上申請了S鎖
查看鎖申請和釋放的順序
我們使用SQL Profiler來跟蹤鎖申請和釋放的事件。
備注:也可以在執行語句前,開啟1200跟蹤標記,使用語句dbcc traceon(1200,-1) (感謝CareySon)
模板選擇TSQL-LOCKS,只跟蹤運行語句的會話spid,同時事件增加Lock:Acquired和Lock:Released。執行查詢跟蹤結果如下:

從上圖可以得出如下信息:
1) 非聚集索引申請的S鎖需等到鍵查找在聚集索引上查找完畢后才釋放。這其實也是鍵查找導致死鎖發生的條件
2)鎖申請和釋放的順序有點類似於進棧和出棧,先申請的最后釋放
3)疑問:為什么沒有鍵查找在聚集索引Key上申請的S鎖記錄呢?鎖肯定是有,但不清楚為什么Profiler沒有記錄到,因為我跟蹤查詢加HOLD時,是會在最后申請一個S鎖的,結果如下:

小結
通過本文,我們知道了一個簡單的鍵查找查詢會申請哪些鎖,同時,鎖申請和釋放的順序是怎樣的。在非聚集索引上申請的鎖一直到鍵查找執行完畢才會釋放
如有不對的地方,歡迎拍磚,謝謝!O(∩_∩)O