SQL Server中的SELECT會(huì)阻塞SELECT嗎
前言
在SQL Server中,我們知道一個(gè)SELECT語(yǔ)句執(zhí)行過(guò)程中只會(huì)申請(qǐng)一些意向共享鎖(IS) 與共享鎖(S), 例如我使用SQL Profile跟蹤會(huì)話86執(zhí)行SELECT * FROM dbo.TEST WHERE OBJECT_ID =1 這個(gè)查詢語(yǔ)句,其申請(qǐng)、釋放的鎖資源的過(guò)程如下所示:

而且從最常見(jiàn)的鎖模式的兼容性表,我們可以看到IS鎖與S鎖都是兼容的,也就是說(shuō)SELECT查詢是不會(huì)阻塞SELECT查詢的。
|
現(xiàn)有的授權(quán)模式 |
||||||
|
請(qǐng)求的模式 |
IS |
S |
U |
IX |
SIX |
X |
|
意向共享 (IS) |
是 |
是 |
是 |
是 |
是 |
否 |
|
共享 (S) |
是 |
是 |
是 |
否 |
否 |
否 |
|
更新 (U) |
是 |
是 |
否 |
否 |
否 |
否 |
|
意向排他 (IX) |
是 |
否 |
否 |
是 |
否 |
否 |
|
意向排他共享(SIX) |
是 |
否 |
否 |
否 |
否 |
否 |
|
排他 (X) |
否 |
否 |
否 |
否 |
否 |
否 |
但是在某些特殊場(chǎng)景。你會(huì)看到SELECT語(yǔ)句居然“阻塞”SELECT操作,那么SQL Server中SELECT會(huì)真的阻塞SELECT操作嗎?我們先構(gòu)造測(cè)試的案例場(chǎng)景,那么先準(zhǔn)備測(cè)試數(shù)據(jù)吧
CREATE TABLE TEST (OBJECT_ID INT, NAME VARCHAR(8)); CREATE INDEX PK_TEST ON TEST(OBJECT_ID) DECLARE @Index INT =0; WHILE @Index < 20 BEGIN INSERT INTO TEST SELECT @Index, 'kerry'; SET @Index = @Index +1; END
在會(huì)話窗口A中,執(zhí)行下面SQL語(yǔ)句,模擬一個(gè)UPDATE語(yǔ)句正在執(zhí)行
BEGIN TRANSACTION UPDATE dbo.TEST SET NAME='Kerry' WHERE OBJECT_ID=1; --ROLLBACK;
會(huì)話窗口B中,執(zhí)行下面的SQL語(yǔ)句
SELECT * FROM dbo.TEST WHERE OBJECT_ID=1
會(huì)話窗口C中,執(zhí)行下面的SQL語(yǔ)句
SELECT * FROM dbo.TEST WHERE OBJECT_ID=1
我實(shí)驗(yàn)的場(chǎng)景下,會(huì)話窗口A的會(huì)話ID為85,會(huì)話窗口B的會(huì)話ID為90,會(huì)話窗口C的會(huì)話ID為87,如下所示

如下所示,你會(huì)看到SELECT語(yǔ)句“阻塞”了SELECT語(yǔ)句,即會(huì)話90“阻塞”了會(huì)話87, 它們的等待事件都為L(zhǎng)CK_M_S,也就是說(shuō)它們都在等待獲取共享鎖,也許你會(huì)置疑這個(gè)SQL是否有問(wèn)題,那么我們使用SP_WHO來(lái)查看,你會(huì)發(fā)現(xiàn)也是如此,如下所示:

如下所示,我們會(huì)發(fā)現(xiàn)會(huì)話ID為90 、87的會(huì)話都在等待類型為RID,Resource為1:24171:1的共享鎖

其實(shí)應(yīng)該說(shuō),會(huì)話87、90都在等待RID對(duì)象的共享鎖,我們知道共享鎖與意向共享鎖都是兼容的,所以SELECT是不會(huì)阻塞SELECT的,那么又怎么解釋這個(gè)現(xiàn)象呢?在宋大神的指點(diǎn)下,粗略的翻了Database System Implementaion這本書(shū)(很多原理性知識(shí),看起來(lái)相當(dāng)吃力)。里面介紹了在鎖表(lock table)以及Element Info、Handling Lock Requests、Handling Unlocks等概念,有一個(gè)有意思的圖所示,

在鎖表(lock table)里,elements info里的鎖的申請(qǐng)是在一個(gè)類似隊(duì)列的結(jié)構(gòu)。先進(jìn)先出機(jī)制,所以當(dāng)會(huì)話90先進(jìn)入隊(duì)列,它在等待共享鎖(S), 會(huì)話87也進(jìn)入隊(duì)列等待共享鎖(S),而且它在會(huì)話90的后面(即會(huì)話90這個(gè)elements info后面的Next指針指向會(huì)話87會(huì)話的事務(wù)),由于兩個(gè)會(huì)話都被阻塞,這兩個(gè)會(huì)話的Wait字段都是Yes,由于內(nèi)部某些機(jī)制,會(huì)話87顯示阻塞它的會(huì)話為90(這個(gè)是我個(gè)人臆測(cè),實(shí)際具體原因有待考究),實(shí)質(zhì)阻塞的源頭還是會(huì)話85. 當(dāng)會(huì)話85釋放排它鎖(X)后,會(huì)話隊(duì)列根據(jù)下面幾個(gè)原則來(lái)處理解鎖(Handling Unlocks):
1: First-come-first-served: Grant the lock request that has been waiting the longest. This strategy guarantees no starvation, the situation where a transaction can wait forever for a lock
先來(lái)先服務(wù)(隊(duì)列的原則):授予鎖等待時(shí)間最長(zhǎng)的鎖請(qǐng)求,這種策略保證不會(huì)餓死(翻譯感覺(jué)不貼切),即一個(gè)事務(wù)不會(huì)永遠(yuǎn)等待鎖的情況。
2. Priority to shared locks: First grant all the shared locks waiting. Then,grant one update lock, if there are any waiting. Only grant an exclusive lock if no others are waiting. This strategy can allow starvation, if a transaction is waiting for a U or X lock.
共享鎖優(yōu)先,首先授予所有等待共享鎖(S),然后授予其中一個(gè)更新鎖(U),如果有其它類型等待,只有在沒(méi)有其它鎖等待時(shí),才授予排它鎖、這一策略允許等待更新鎖或排它鎖的事務(wù)餓死(結(jié)束)
3. Priority to upgrading: If there is a transaction with a U lock waiting to upgrade it to an X lock, grant that first. Otherwise, follow one of the other strategies mentioned.
鎖升級(jí)優(yōu)先,如果有一個(gè)持有共享鎖(U)等待升級(jí)Wie排他鎖(X),那么先授予它排它鎖,否則采用前面已經(jīng)提到的策略中的一個(gè)。
按照這些原則,當(dāng)會(huì)話85釋放了排它鎖(X)后,調(diào)度器(Scheduler)應(yīng)該會(huì)根據(jù)先后順序依次授予會(huì)話90、87共享鎖(S),兩者的阻塞會(huì)幾乎同時(shí)消失。 這個(gè)可以也可以通過(guò)實(shí)驗(yàn)進(jìn)行一個(gè)大概的推斷, 在上面實(shí)驗(yàn)中,你可以手工取消90會(huì)話的查詢操作,然后再查看阻塞情況,就會(huì)發(fā)現(xiàn)會(huì)話87被85阻塞了。這個(gè)阻塞的源頭就變成了85,而不是90了。
PS:上面是個(gè)人結(jié)合一些知識(shí)和理解,做的一些膚淺的判斷與分析,如果不對(duì)的地方,敬請(qǐng)指正!
參考資料:
Database System Implementaion
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
- SQL Server 2008數(shù)據(jù)庫(kù)分布式查詢知識(shí)
- SQL Server游標(biāo)的介紹與使用
- SQL Server三種鎖定模式的知識(shí)講解
- SQL Server視圖的講解
- Sql Server的一些知識(shí)點(diǎn)定義總結(jié)
- C#連接SQL Server的實(shí)現(xiàn)方法
- laravel5使用freetds連接sql server的方法
- 詳解易語(yǔ)言操作sql server實(shí)例
- sqlserver2008首次登錄失敗問(wèn)題及解決方法
- SQL Server四個(gè)系統(tǒng)表的知識(shí)講解
相關(guān)文章
一個(gè)簡(jiǎn)單的SQL 行列轉(zhuǎn)換語(yǔ)句
在數(shù)據(jù)庫(kù)開(kāi)發(fā)中經(jīng)常會(huì)遇到行列轉(zhuǎn)換的問(wèn)題,比如下面的問(wèn)題,部門(mén),員工和員工類型三張表,我們要統(tǒng)計(jì)類似這樣的列表2009-08-08
sql2000報(bào)錯(cuò)Successfully re-opened the local eventlog解決方法
這篇文章主要介紹了sql2000報(bào)錯(cuò)Successfully re-opened the local eventlog解決方法,需要的朋友可以參考下2014-12-12
SQL Server數(shù)據(jù)庫(kù)文件過(guò)大而無(wú)法直接導(dǎo)出解決方案
這篇文章主要介紹了SQL Server數(shù)據(jù)庫(kù)文件過(guò)大而無(wú)法直接導(dǎo)出解決方案,文中通過(guò)代碼示例講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-08-08
Sqlserver事務(wù)備份和還原的實(shí)例代碼(必看)
下面小編就為大家?guī)?lái)一篇Sqlserver事務(wù)備份和還原的實(shí)例代碼(必看)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-05-05
sql server通過(guò)腳本進(jìn)行數(shù)據(jù)庫(kù)壓縮全備份的方法【推薦】
這篇文章主要介紹了sql server通過(guò)腳本進(jìn)行數(shù)據(jù)庫(kù)壓縮全備份的方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-06-06
sql語(yǔ)句中單引號(hào),雙引號(hào)的處理方法
關(guān)于Insert字符串 很多同學(xué)都在(單引號(hào),雙引號(hào))這個(gè)方面發(fā)生了問(wèn)題,其實(shí)主要是因?yàn)閿?shù)據(jù)類型和變量在作怪。2013-03-03
SQL server 中 CROSS APPLY的使用及用途
CROSS APPLY是SQL Server中的操作符,用于將表表達(dá)式與外部表連接,它允許在查詢中多次引用外部表的行,并根據(jù)每行動(dòng)態(tài)生成結(jié)果集,而OUTER APPLY則類似于LEFT JOIN,后者即使子查詢無(wú)結(jié)果也會(huì)顯示外部表的行,感興趣的朋友跟隨小編一起看看吧2024-11-11
SqlServer使用 case when 解決多條件模糊查詢問(wèn)題
這篇文章主要介紹了SqlServer使用 case when 解決多條件模糊查詢問(wèn)題 的相關(guān)資料,需要的朋友可以參考下2015-12-12
SqlServer 數(shù)據(jù)庫(kù) 三大 范式
本文將基于三大范式原則,結(jié)合具體的實(shí)例做簡(jiǎn)要分析,對(duì)SqlServer 數(shù)據(jù)庫(kù) 三大 范式相關(guān)知識(shí)感興趣的朋友一起看看吧2019-11-11

