Sql-Server

SQL Server 中的鍵範圍 RangeI-N 鎖兼容性

  • November 11, 2019

文件指出RangeI -N 鎖(插入範圍,空資源鎖;用於在將新鍵插入索引之前測試範圍)與自身兼容(請參閱兼容性矩陣),因此即使一個事務已獲得 RangeI -N lock on specific key 另一個事務也可以獲得這樣的鎖。

在下面,它說

在事務中插入值時,在執行插入操作的事務期間不必鎖定值所屬的範圍。鎖定插入的鍵值直到事務結束就足以保持可序列化性。例如,給定這個 INSERT 語句:

INSERT mytable VALUES (‘Dan’);

RangeI-N模式key-range鎖被放置在名字David對應的索引條目上,以測試範圍。如果授予鎖,則插入 Dan 並在值 Dan 上放置排他 (X) 鎖。RangeI-N 模式鍵範圍鎖僅在測試範圍時是必需的,並且不會在執行插入操作的事務期間保持。其他事務可以在插入值 Dan 之前或之後插入或刪除值。但是,任何試圖讀取、插入或刪除值 Dan 的事務都將被鎖定,直到插入事務送出或回滾。

引用另一個來源- Microsoft SQL Server 2008 Internals:事務和並發:

例如,當 SQL Server 嘗試使用 Serializable 隔離在會話中的鍵之間插入範圍時,將獲取 RangeIn-Null 鎖。這種類型的鎖並不常見,因為它通常是非常短暫的。直到找到正確的插入位置,它才會被持有,然後鎖被轉換為 X 鎖。

我的理解是,這種類型的鎖是在辨識新插入的鑰匙應該放置的範圍的過程中(我假設這就是“測試範圍”的意思)。發生這種情況後,鎖被釋放,插入新密鑰並在其上放置 X 鎖。

但是我不明白為什麼說兩個 RangeI-N 鎖相互兼容。如果事務 A 和 B 都在同一個鍵上放置 RangeI-N 鎖,因為它們都想在範圍中插入一個新鍵,並且事務 A 先執行插入,那麼 B 確定的鍵插入位置可能已經不正確,因為範圍已更改(A 在那裡插入了一個新值)。誰能解釋一下?

我的理解是,這種類型的鎖是在辨識新插入的鑰匙應該放置的範圍的過程中(我假設這就是“測試範圍”的意思)。發生這種情況後,鎖被釋放,插入新密鑰並在其上放置 X 鎖。

RangeI-N請求鎖以測試插入鍵範圍不會干擾另一個事務,該事務可能會執行一些與插入不兼容的可序列化操作(例如讀取)。

在將記錄插入索引期間,數據庫引擎會定位頁面,插入的鍵應該放置在哪裡。在這個階段還沒有使用頁面鎖和鑰匙鎖,只有閂鎖。一旦找到頁面,引擎就會開始獲取執行向頁面插入記錄所必需的鎖。這些是IX定位頁面的鎖定,然後RangeI-N鎖定插入的密鑰旁邊的密鑰。在獲取時RangeI-N不保持,並且X請求對正在插入的密鑰進行下一次鎖定。在獲得必要的鎖之後,繼續插入記錄。

假設我們有表格和數據

CREATE TABLE T
(
   K int NOT NULL,
   CONSTRAINT UQ_T UNIQUE CLUSTERED (K)
);

INSERT INTO T (K)
VALUES (1), (2), (9), (10);

讓我們獲取以下查詢的結果

SELECT K, %%lockres%% AS lockres
FROM T;

這是

K    lockres
---- ---------------
1    (8194443284a0)
2    (61a06abd401c)
9    (30b7763ed433)
10   (d08358b1108f)

(我們將在後面提到它)。

然後,假設我們有一個查詢

SELECT COUNT(*)
FROM T
WHERE K BETWEEN 1 AND 9;

在隔離級別下執行它會SERIALIZABLE導致以下鎖定足跡

SELECT 鎖定足跡

為了保護密鑰範圍,數據庫引擎用鎖鎖定該範圍內的每個密鑰RangeS-S。此外,範圍旁邊的鍵被鎖定(這對於非唯一索引是必要的,但引擎也在為唯一索引執行此操作)。在這種情況下,鎖被放置在與鍵 1、2、9 和 10 對應的資源上(根據之前的查詢結果)。

非並發插入到表中

INSERT INTO T (K)
VALUES (3);

結果跟隨鎖定足跡

插入鎖定足跡

表中不存在鍵 3,因此數據庫引擎請求RangeI-N鎖定與鍵 9 對應的資源*(30b7763ed433) ,此時鍵 3 旁邊。獲取RangeI-N意味著沒有執行不兼容的可序列化活動,因此引擎繼續並獲取與密鑰 3 對應X的資源(98ec012aa510)*上的鎖。然後實際插入發生並釋放鎖。請注意,沒有釋放RangeI-N鎖。

在上面執行SELECTINSERT同時導致INSERT等待直到執行可序列化的事務SELECT處於活動狀態

SELECT 和 INSERT 並發

因為RangeI-N不兼容RangeS-S。一旦交易執行SELECT結束INSERT,將繼續進行。

這就是“測試範圍”的意思。


但是我不明白為什麼說兩個 RangeI-N 鎖相互兼容。

RangeI-N鎖兼容性很好,因為它允許並發插入鍵範圍。

想像我們正在做

INSERT INTO T (K)
VALUES (4);

INSERT INTO T (K)
VALUES (6);

同時。

可能在某個時刻,兩個語句都在與鍵 9 對應RangeI-N的資源*(30b7763ed433)*上獲取。但這很好,因為這樣並發性由X鍵和頁鎖存器進一步控制。

引用自:https://dba.stackexchange.com/questions/252430