死鎖過程:
- 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
很神奇,這樣設置后,死鎖的問題就不存在了。
查詢是否設置成功:
select is_read_committed_snapshot_on from sys.databases where name = DB_Name()