前段時(shí)間有朋友問:SQL Server的AlwaysOn的輔助數(shù)據(jù)庫默認(rèn)會(huì)使用行版本快照控制來消除數(shù)據(jù)庫上的讀寫事務(wù)阻塞和死鎖問題
即使用戶顯式為查詢設(shè)置了其他事務(wù)隔離級別,所有鎖提示(Lock Hint)都會(huì)被忽略。
為了保證數(shù)據(jù)同步的完整性,AlwaysOn規(guī)定來自數(shù)據(jù)同步(redo 日志)所做的寫操作永遠(yuǎn)不會(huì)被選為死鎖犧牲品,無論該寫操作的代價(jià)多小。
AlwaysOn的做法其實(shí)很好理解,數(shù)據(jù)庫中的事務(wù)操作無非就四種
1、讀讀
2、讀寫
3、寫讀
4、寫寫
第二種、第三種和第四種造成阻塞和死鎖很容易理解,讀事務(wù)得到的鎖資源不釋放就有可能造成寫事務(wù)失敗或者寫事務(wù)得到的鎖資源不釋放就有可能造成讀事務(wù)
但是第一種讀讀事務(wù)也會(huì)造成死鎖嗎?
我這里做一個(gè)實(shí)驗(yàn)
1、先確保數(shù)據(jù)庫沒有使用任何快照隔離級別
USE [tt1]DBCC USEROPTIONS
2、腳本1
USE [tt1];SET TRANSACTION ISOLATION LEVEL SERIALIZABLEBEGIN TRANSELECT * FROM [dbo].[Table_1] WITH (ROWLOCK) WHERE [q]=88
3、腳本2
USE [tt1];SET TRANSACTION ISOLATION LEVEL SERIALIZABLEBEGIN TRANSELECT * FROM [dbo].[Storage] WITH (TABLOCKX)SELECT * FROM [dbo].[Table_1] WHERE [q]=7
4、腳本3
USE [tt1];SET TRANSACTION ISOLATION LEVEL SERIALIZABLEBEGIN TRANSELECT * FROM [dbo].[Table_1] WITH (ROWLOCK) WHERE [q]=88
5、腳本4
USE [tt1];SET TRANSACTION ISOLATION LEVEL SERIALIZABLEBEGIN TRANSELECT * FROM [dbo].[Table_1] WITH (ROWLOCK)
6、在多個(gè)查詢窗口(session)里執(zhí)行上面的腳本
7、打開跟蹤標(biāo)記
DBCC TRACEON (1204, 1222, -1); DBCC tracestatus
8、過一會(huì)兒就會(huì)看到其中一個(gè)session 59已經(jīng)作為死鎖犧牲品
9、在errorlog里已經(jīng)看到spid為4的死鎖監(jiān)視器(LOCK MONITOR)已經(jīng)監(jiān)測到死鎖的存在
EXEC xp_readerrorlog 0,1,NULL,NULL,'2015-08-06','2015-10-10','DESC'
總結(jié)
多人都不了解為什么SELECT語句也會(huì)產(chǎn)生死鎖,其實(shí)SELECT語句一般在RC隔離級別下很少會(huì)發(fā)送死鎖,只是用戶在日常開發(fā)中會(huì)使用了一些不恰當(dāng)?shù)逆i提示(Lock Hint)或者提升了事務(wù)隔離級別而導(dǎo)致
日常開發(fā)中我們都要注意不要濫用鎖提示(Lock Hint),根據(jù)實(shí)際情況進(jìn)行判斷,該提升事務(wù)隔離級別就提升事務(wù)隔離級別,以免造成不必要的死鎖。
如有不對的地方,歡迎大家拍磚o(∩_∩)o
新聞熱點(diǎn)
疑難解答
圖片精選