索引鍵範圍鎖定

使用可序列化的交易隔離等級時,索引鍵範圍鎖定可保護由 Transact-SQL 陳述式讀取之記錄集中隱含包括的資料列範圍。可序列化的隔離等級要求在交易期間執行的任何查詢,在交易期間每次執行時都必須取得相同的資料列集。索引鍵範圍鎖定藉由預防其他交易插入新資料列時,這些資料列的索引鍵落在可序列化交易讀取的索引鍵範圍,來保護此種需求。

索引鍵範圍鎖定可預防幽靈讀取。藉由保護資料列之間的索引鍵範圍,也可以預防幽靈插入到交易存取的記錄集。

索引鍵範圍鎖定是放置於索引之上,指定開始和結束的索引鍵值。因為這些動作會先在索引上取得鎖定,因此這種鎖定可封鎖任何嘗試插入、更新或刪除含有索引鍵值落入範圍的任何資料列。例如,可序列化的交易可能會發出 SELECT 陳述式,讀取其索引鍵值在 'AAA''CZZ' 之間的所有資料列。從 'AAA''CZZ' 範圍中索引鍵值的索引鍵範圍鎖定,可預防其他交易將含有索引鍵值的資料列插入到該範圍內的任何地方,例如 'ADG''BBD''CAL'

索引鍵範圍鎖定模式

索引鍵範圍鎖定包括範圍以及資料列元件,以範圍-資料列的格式來指定:

  • 範圍代表保護兩個連續索引項之間的範圍的鎖定模式。

  • 資料列代表保護索引項的鎖定模式。

  • 模式代表所使用的合併鎖定模式。索引鍵範圍鎖定模式由兩個部份組成。第一個部份代表用來鎖定索引鍵範圍的鎖定類型 (RangeT),第二個部份代表用來鎖定特定索引鍵的鎖定類型 (K)。這兩個部份使用連字號 (-) 來連接,例如 RangeT-K

    範圍

    資料列

    模式

    描述

    RangeS

    S

    RangeS-S

    共用範圍,共用資源鎖定;可序列化範圍掃描。

    RangeS

    U

    RangeS-U

    共用範圍,更新資源鎖定;可序列化更新掃描。

    RangeI

    Null

    RangeI-N

    插入範圍,Null 資源鎖定;在插入新的索引鍵到索引之前用來測試範圍。

    RangeX

    X

    RangeX-X

    獨占範圍,獨占資源鎖定;在範圍內更新索引鍵時使用。

[!附註]

內部的 Null 鎖定模式與其他所有的鎖定模式皆相容。

索引鍵範圍鎖定模式的相容性矩陣顯示,哪些鎖定與重疊索引鍵和範圍中取得的其他鎖定相容。如需鎖定相容性的完整矩陣,請參閱<鎖定相容性>。

 

現有已授與的模式

 

 

 

 

 

 

要求的模式

S

U

X

RangeS-S

RangeS-U

RangeI-N

RangeX-X

共用 (S)

更新 (U)

獨占 (X)

RangeS-S

RangeS-U

RangeI-N

RangeX-X

轉換鎖定

轉換鎖定是在索引鍵範圍鎖定與另一種鎖定重疊時建立。

鎖定 1

鎖定 2

轉換鎖定

S

RangeI-N

RangeI-S

U

RangeI-N

RangeI-U

X

RangeI-N

RangeI-X

RangeI-N

RangeS-S

RangeX-S

RangeI-N

RangeS-U

RangeX-U

在不同的複雜環境下,可以觀察到短期的轉換鎖定,有時是在並行的處理序執行時。

可序列化範圍掃描、單一擷取、刪除以及插入

索引鍵範圍鎖定可確保下列動作是可序列化:

  • 範圍掃描查詢

  • 單一擷取不存在的資料列

  • 刪除動作

  • 插入動作

在索引鍵範圍鎖定發生之前,必須滿足下列條件:

  • 交易隔離等級必須設為 SERIALIZABLE。

  • 查詢處理器必須使用索引來實作範圍篩選述詞。例如,SELECT 陳述式中的 WHERE 子句可能會建立一個範圍條件含有此述詞:ColumnX BETWEEN N**'AAA'** AND N**'CZZ'**。如果 ColumnX 涵蓋在索引鍵中,才會取得索引鍵範圍鎖定。

範例

下列資料表和索引是用來作為索引鍵範圍鎖定範例要遵循的基礎。

具有索引 B 型樹狀的資料庫資料表圖例

範圍掃描查詢

為了確保範圍掃描查詢是可序列化,相同的查詢每次在相同交易內執行時都必須傳回相同的結果。其他的交易絕不能把新的資料列插入範圍掃描查詢內;否則這些動作將會變成幽靈插入。例如,以下的查詢使用上述的資料表與索引:

SELECT name
    FROM mytable
    WHERE name BETWEEN 'A' AND 'C';

放置索引鍵範圍鎖定的索引項對應到名稱介於資料值 Adam 與 Dale 之間的資料列範圍,讓前次查詢中限定的新資料列無法新增或刪除。雖然此範圍內的第一個名稱是 Adam,但位於此索引項的 RangeS-S 模式的索引鍵範圍鎖定會確保以字母 A 開頭的新名稱無法新增至 Adam 前面,例如 Abigail。同樣的,位於 Dale 的索引項的 RangeS-S 索引鍵範圍鎖定,則確保以字母 C 開頭的新名稱皆無法新增至 Carlos 後面,例如 Clive。

[!附註]

持有的 RangeS-S 鎖定的數量為 n+1,其中 n 為符合查詢的資料列數量。

單一擷取不存在的資料

如果交易內的查詢嘗試選取不存在的資料列,則在同一筆交易內稍後的某一點所提交的查詢必須傳回相同的結果。其他的任何交易皆不得插入這個不存在的資料列。例如,給定以下的查詢:

SELECT name
    FROM mytable
    WHERE name = 'Bill';

將索引鍵範圍鎖定放在與名稱範圍從 Ben 到 Bing 對應的索引項,因為要把名稱 Bill 插入這兩個相鄰的索引項之間。將 RangeS-S 模式的索引鍵範圍鎖定放在索引項 Bing 之上。這可預防其他交易將值 (例如 Bill) 插入到索引項 Ben 和 Bing 之間。

刪除動作

在交易內刪除某個值時,交易進行刪除動作期間不需鎖定該值所處之範圍。鎖定欲刪除的索引鍵值直到交易結束,即足以維持可序列化能力。例如,給定以下的 DELETE 陳述式:

DELETE mytable
    WHERE name = 'Bob';

將獨占 (X) 鎖定放在與名稱 Bob 對應的索引項。其他交易可在被刪除的值 Bob 前後插入或刪除值。但是,嘗試讀取、插入或是刪除 Bob 這個值的任何交易,在進行刪除動作的交易尚未認可或回復之前都會被封鎖。

可以使用三種基本鎖定模式來執行範圍刪除:資料列、分頁或資料表鎖定。資料列、分頁或資料表的鎖定策略是由查詢最佳化工具來決定,或者亦可由使用者透過最佳化提示 (如 ROWLOCK、PAGLOCK 或 TABLOCK) 來指定。使用 PAGLOCK 或 TABLOCK 時,如果所有資料列都會從此分頁刪除,Database Engine 會立即重新配置索引頁。相反的,若是使用 ROWLOCK,所有已刪除的資料列則僅標示為已刪除;稍後再使用背景工作將這些資料列從索引頁中移除。

插入動作

在交易內插入某個值時,交易進行插入動作期間不需鎖定該值所處之範圍。鎖定欲插入的索引鍵值直到交易結束,即足以維持可序列化能力。例如,給定以下的 INSERT 陳述式:

INSERT mytable VALUES ('Dan');

將 RangeI-N 模式的索引鍵範圍鎖定放在與名稱 David 對應的索引項來測試範圍。如果授與鎖定,便插入 Dan 並將獨占 (X) 鎖定放在 Dan 這個值。RangeI-N 模式的索引鍵範圍鎖定只有在測試範圍時才需要,且在交易進行插入動作期間不需持有。其他的交易皆可在插入值 Dan 的前面或後面插入或刪除值。但是,嘗試讀取、插入或是刪除 Dan 這個值的任何交易在進行插入動作的交易尚未認可或回復之前都會被鎖定。