Select語句也會引發死鎖

  項目上線,準備驗收前出現了一個嚴重的問題:不少select語句做爲死鎖的犧牲,大部分報表沒法打開。這個問題影響範圍很大全部的報表都沒法訪問,而咱們的報表是放在電視上面輪播的,電視放在工廠裏面,因此出現問題後,整個工廠都知道了。html

  解決這個問題比較曲折,首先是寫SAP接口的同事發現了問題:SAP一直在傳錯誤數據致使產量表被鎖住。修改SAP傳輸的錯誤數據後,這個死鎖的問題沒有出現了。可是我查看生產環境服務器日誌的時候,發現這個問題依然存在,因爲客戶沒有提這個問題,我也就是沒有理由要求花時間修改了,由於我還有其餘項目在忙。sql

  問題始終存在,它的暴露只是時間問題。過了一週,在咱們要談項目驗收的時候,這個問題又暴露出來了。由於影響很是大,給客戶形成很差的印象。因此修改這個問題獲得了老闆的支持,說實話,我也頭一次遇到這樣的問題,也想不通select語句怎麼就死鎖了。我知道這個問題很頭疼,好在獲得老闆的支持,會給足夠的時候我來解決問題,我也就有信心了。數據庫

  在網上找了不少文章,個人解決思路是:經過查詢語句查找死鎖相關的sql語句,只發現了被犧牲的那條sql語句,另一條sql語句沒有找到,這條路走不通。接着就是重現問題,而後解決問題。這條路剛開始也走不通,也行不通,重現了一個下午有沒有發現問題。在快下班的時候,我迷茫了。次日又網上找了半天資料,這個時候想到用sql server profiler去監聽數據庫,悲劇的是客戶那邊放假了,連不到出問題的生產環境數據庫。接着跟同事聊這個問題,他給的建議依然是重現,而後記得有個方法能夠重現,這個時候我才猛然想起來了有這檔子事。服務器

  重現方法是有sql語句循環往產量表插入數據,因爲報表大多讀取產量表,而後報表就常常死鎖。這個時候我看到但願了,只是不理解select語句怎麼會引發死鎖,後來在網上認真讀了一篇文章:SqlServer中select語句引發的死鎖(http://www.csharpwin.com/csharpspace/11505r288.shtml),讀懂這篇文章後我以爲跟我遇到的狀況很是類似。spa

  經過他的理論我分析了下死鎖過程:版本控制

  • select語句使用非聚族索引查詢產量信息,會對非聚族索引添加共享鎖,因爲非聚族索引上沒有select的所有數據列,(因此會有書籤查找出現,)須要查詢產量表。查詢產量表時,須要對產量表數據添加共享鎖,須要等待Update語句更新完產量表後釋放排他鎖。即Select等待Update釋放鎖。
  • 此時產量表上的Update/Insert語句更新產量信息的時候,會在聚族索引上作定位,添加排他鎖和修改非聚族索引的信息,問題就出在修改非聚族索引信息的時候,須要對非聚族作索引添加排他鎖。此時select語句已經在聚族索引上面添加了共享鎖,須要釋放後才能被添加排他鎖。即update語句須要等待select語句是否鎖。
  • 這樣死鎖就造成了。
 
因而只要讓查詢語句加共享鎖就解決問題了,sql server行版本級別控制能解決個人問題。

使用基於行版本控制的隔離級別:當在基於行版本控制的隔離下運行的事務讀取數據時,讀取操做不會獲取正被讀取的數據上的共享鎖(S 鎖)日誌

找到最快設置行版本級別的方法:
 
複製代碼
if(charindex('Microsoft SQL Server 2008',@@version) > 0) 
begin 

declare @sql varchar(8000) 
select @sql = ' 
ALTER DATABASE ' + DB_NAME() + ' SET SINGLE_USER WITH ROLLBACK IMMEDIATE ; 
ALTER DATABASE ' + DB_NAME() + ' SET READ_COMMITTED_SNAPSHOT ON; 
ALTER DATABASE ' + DB_NAME() + ' SET MULTI_USER;' 

Exec(@sql) 
end 
複製代碼

很神奇,這樣設置後,死鎖的問題就不存在了。code

 

查詢是否設置成功:
select is_read_committed_snapshot_on from sys.databases where name = DB_Name()  server

相關文章
相關標籤/搜索