共計 2675 個字符,預計需要花費 7 分鐘才能閱讀完成。
這篇文章給大家分享的是有關 SQL Server 中的 SELECT 會不會阻塞 SELECT 的內容。丸趣 TV 小編覺得挺實用的,因此分享給大家做個參考,一起跟隨丸趣 TV 小編過來看看吧。
前言
在 SQL Server 中,我們知道一個 SELECT 語句執行過程中只會申請一些意向共享鎖 (IS) 與共享鎖 (S), 例如我使用 SQL Profile 跟蹤會話 86 執行 SELECT * FROM dbo.TEST WHERE OBJECT_ID =1 這個查詢語句,其申請、釋放的鎖資源的過程如下所示:
而且從最常見的鎖模式的兼容性表,我們可以看到 IS 鎖與 S 鎖都是兼容的,也就是說 SELECT 查詢是不會阻塞 SELECT 查詢的。
現有的授權模式
請求的模式
IS
S
U
IX
SIX
X
意向共享 (IS)
是
是
是
是
是
否
共享 (S)
是
是
是
否
否
否
更新 (U)
是
是
否
否
否
否
意向排他 (IX)
是
否
否
是
否
否
意向排他共享 (SIX)
是
否
否
否
否
否
排他 (X)
否
否
否
否
否
否
但是在某些特殊場景。你會看到 SELECT 語句居然“阻塞”SELECT 操作,那么 SQL Server 中 SELECT 會真的阻塞 SELECT 操作嗎?我們先構造測試的案例場景,那么先準備測試數據吧
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
在會話窗口 A 中,執行下面 SQL 語句,模擬一個 UPDATE 語句正在執行
BEGIN TRANSACTION
UPDATE dbo.TEST SET NAME= Kerry WHERE OBJECT_ID=1;
--ROLLBACK;
會話窗口 B 中,執行下面的 SQL 語句
SELECT * FROM dbo.TEST WHERE OBJECT_ID=1
會話窗口 C 中,執行下面的 SQL 語句
SELECT * FROM dbo.TEST WHERE OBJECT_ID=1
我實驗的場景下,會話窗口 A 的會話 ID 為 85,會話窗口 B 的會話 ID 為 90, 會話窗口 C 的會話 ID 為 87,如下所示
如下所示,你會看到 SELECT 語句“阻塞”了 SELECT 語句,即會話 90“阻塞”了會話 87,它們的等待事件都為 LCK_M_S, 也就是說它們都在等待獲取共享鎖,也許你會置疑這個 SQL 是否有問題,那么我們使用 SP_WHO 來查看,你會發現也是如此,如下所示:
如下所示,我們會發現會話 ID 為 90、87 的會話都在等待類型為 RID,Resource 為 1:24171:1 的共享鎖
其實應該說,會話 87、90 都在等待 RID 對象的共享鎖,我們知道共享鎖與意向共享鎖都是兼容的,所以 SELECT 是不會阻塞 SELECT 的,那么又怎么解釋這個現象呢?在宋大神的指點下,粗略的翻了 Database System Implementaion 這本書(很多原理性知識,看起來相當吃力)。里面介紹了在鎖表(lock table)以及 Element Info、Handling Lock Requests、Handling Unlocks 等概念, 有一個有意思的圖所示,
在鎖表(lock table)里,elements info 里的鎖的申請是在一個類似隊列的結構。先進先出機制,所以當會話 90 先進入隊列,它在等待共享鎖(S), 會話 87 也進入隊列等待共享鎖 (S),而且它在會話 90 的后面(即會話 90 這個 elements info 后面的 Next 指針指向會話 87 會話的事務), 由于兩個會話都被阻塞,這兩個會話的 Wait 字段都是 Yes,由于內部某些機制,會話 87 顯示阻塞它的會話為 90(這個是我個人臆測,實際具體原因有待考究),實質阻塞的源頭還是會話 85. 當會話 85 釋放排它鎖(X)后,會話隊列根據下面幾個原則來處理解鎖(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
先來先服務(隊列的原則):授予鎖等待時間最長的鎖請求,這種策略保證不會餓死(翻譯感覺不貼切),即一個事務不會永遠等待鎖的情況。
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.
共享鎖優先,首先授予所有等待共享鎖(S),然后授予其中一個更新鎖(U), 如果有其它類型等待,只有在沒有其它鎖等待時,才授予排它鎖、這一策略允許等待更新鎖或排它鎖的事務餓死(結束)
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.
鎖升級優先,如果有一個持有共享鎖(U) 等待升級 Wie 排他鎖(X), 那么先授予它排它鎖,否則采用前面已經提到的策略中的一個。
按照這些原則,當會話 85 釋放了排它鎖(X) 后,調度器(Scheduler)應該會根據先后順序依次授予會話 90、87 共享鎖(S), 兩者的阻塞會幾乎同時消失。這個可以也可以通過實驗進行一個大概的推斷,在上面實驗中,你可以手工取消 90 會話的查詢操作,然后再查看阻塞情況,就會發現會話 87 被 85 阻塞了。這個阻塞的源頭就變成了 85,而不是 90 了。
感謝各位的閱讀!關于“SQL Server 中的 SELECT 會不會阻塞 SELECT”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!