最近遇到的死鎖問題都發生在併發操作單張表上,比較有意思,就模擬了重現了一下。根據非聚集索引為條件,刪除某一個表的數據,類似於這麼一個語句,delete from table where nocluster_index in (x,y,z,m,n……)in裡面的內容不同,併發執行某些情況下,可能會引發 ...
最近遇到的死鎖問題都發生在併發操作單張表上,比較有意思,就模擬了重現了一下。
根據非聚集索引為條件,刪除某一個表的數據,類似於這麼一個語句,delete from table where nocluster_index in (x,y,z,m,n……)in裡面的內容不同,併發執行
某些情況下,可能會引發死鎖,如下簡單模擬重現一下這種情況。
如下用兩張表來模擬上述場景:TestPageLock代表要刪除的表,TestId來存儲用來刪除的Id
如下,用兩個Session即可,模擬併發,很快就會看到一條死鎖的信息
擴展事件ring_buffer target中中的死鎖日誌
原理不難理解:
不同的Session要刪除的數據分佈在不同的數據頁面中,執行delete語句刪除數據的情況下,也是一個查找然後加鎖的過程
當要刪除的數據落在不同的數據頁面上的時候,一旦加鎖順序發生衝突,就會產生死鎖
比如Session1刪除的數據分佈在50,80,120頁面上,Session2刪除的數據分佈在100,120,140頁面上,
Session1和Session2 要加鎖的目標存在交集,一旦存在交集,併發情況就可能存在加鎖順序衝突,類似死鎖因此而產生
解決:
最最簡單暴力的就是顯式鎖提示,這裡只能是tablockx;高級一點,遇到類似併發業務,可以使用隊列進行排隊。
估計會有人擔心tablockx的性能問題會不會鎖的太多了,測試發現直接顯式tablockx鎖提示,並不會非常大地影響性能,整體性能甚至會變高,
因為tablockx鎖模式更加簡單直接,會比行數需要的資源更少,因此在鎖定資源上,處理起來比較高效。