項目上線,準備驗收前出現了一個嚴重的問題:很多select語句作為死鎖的犧牲,大部分報表無法打開。這個問題影響范圍很大所有的報表都無法訪問,而我們的報表是放在電視上面輪播的,電視放在工廠里面,所以出現問題后,整個工廠都知道了。
解決這個問題比較曲折,首先是寫SAP接口的同事發現了問題:SAP一直在傳錯誤數據導致產量表被鎖住。修改SAP傳輸的錯誤數據后,這個死鎖的問題沒有出現了。但是我查看生產環境服務器日志的時候,發現這個問題依然存在,由于客戶沒有提這個問題,我也就是沒有理由要求花時間修改了,因為我還有其他項目在忙。
問題始終存在,它的暴露只是時間問題。過了一周,在我們要談項目驗收的時候,這個問題又暴露出來了。因為影響非常大,給客戶造成不好的印象。所以修改這個問題得到了老板的支持,說實話,我也頭一次遇到這樣的問題,也想不通select語句怎么就死鎖了。我知道這個問題很頭疼,好在得到老板的支持,會給足夠的時候我來解決問題,我也就有信心了。
在網上找了很多文章,我的解決思路是:通過查詢語句查找死鎖相關的sql語句,只發現了被犧牲的那條sql語句,另外一條sql語句沒有找到,這條路走不通。接著就是重現問題,然后解決問題。這條路剛開始也走不通,也行不通,重現了一個下午有沒有發現問題。在快下班的時候,我迷茫了。第二天又網上找了半天資料,這個時候想到用sql server PRofiler去監聽數據庫,悲劇的是客戶那邊放假了,連不到出問題的生產環境數據庫。接著跟同事聊這個問題,他給的建議依然是重現,然后記得有個方法可以重現,這個時候我才猛然想起來了有這檔子事。
重現方法是有sql語句循環往產量表插入數據,由于報表大多讀取產量表,然后報表就經常死鎖。這個時候我看到希望了,只是不理解select語句怎么會引起死鎖,后來在網上認真讀了一篇文章:SqlServer中select語句引起的死鎖(http://www.csharpwin.com/csharpspace/11505r288.shtml),讀懂這篇文章后我覺得跟我遇到的情況非常相似。
通過他的理論我分析了下死鎖過程:
使用基于行版本控制的隔離級別:當在基于行版本控制的隔離下運行的事務讀取數據時,讀取操作不會獲取正被讀取的數據上的共享鎖(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
很神奇,這樣設置后,死鎖的問題就不存在了。
查詢是否設置成功:select is_read_committed_snapshot_on from sys.databases where name = DB_Name()
新聞熱點
疑難解答