Sql-Server

SQL Server - RangeX-X 和 RangeI-N 鎖

  • September 5, 2020

我在死鎖分析中遇到了一個死點。根據msdn

RangeX-X是Exclusive range,獨占資源鎖;在更新範圍​​內的鍵時使用。RangeI-N 為插入範圍,空資源鎖;用於在將新鍵插入索引之前測試範圍。

所以我明白,如果我在 2 個鍵列上有一個索引 - 並且我插入一個新鍵,我將擁有 RangeI-N 鎖,但如果我從索引更新現有鍵,我將擁有 RangeX-X。

但我的問題或多或少有點複雜。假設我在 A、B 列和 C 列上有索引 IX_keys_included。

在可序列化隔離模式下,我為包含的列 C 插入一個新值。索引 IX_keys_included 會有 RangeI-N 或 RangeX-X 鎖嗎?實際上,考慮到我在索引中為包含的列插入新列,是否會有任何鎖?

我自己想到了這一點,並在我的部落格上寫道。對於那些對解決方案感興趣的人,請訪問此文章:RangeS-SRangeS-URangeX-X

注意:上面的連結已被修改為指向 archive.org,因為該站點不再有效。很不幸。此外,部落格的內容非常廣泛,或者我會嘗試將其中的一些數據擷取到這裡。一篇文章實在是太多了。~ jcolebrand
PS:如果您點擊這些連結,請不要忘記在archive.org 上花幾美元。

所以我明白,如果我在 2 個鍵列上有一個索引 - 並且我插入一個新鍵,我將擁有 RangeI-N 鎖,但如果我從索引更新現有鍵,我將擁有 RangeX-X。

從關於可序列化操作的文件中(強調添加):

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

INSERT mytable VALUES ('Dan');

RangeI-N模式key-range鎖被放置在名字David對應的索引條目上,以測試範圍。如果授予鎖,則插入 Dan 並在值 Dan 上放置排他 (X) 鎖。 RangeI-N 模式鍵範圍鎖僅在測試範圍時是必需的,並且不會在執行插入操作的事務期間保持。

請注意,無論它在何種隔離下執行,插入都會測試範圍,以確保與在可序列化隔離級別上執行的任何其他並發事務兼容。


但我的問題或多或少有點複雜。假設我在 A、B 列和 C 列上有索引 IX_keys_included。

在可序列化隔離模式下,我為包含的列 C 插入一個新值。索引 IX_keys_included 會有 RangeI-N 或 RangeX-X 鎖嗎?實際上,考慮到我在索引中為包含的列插入新列,是否會有任何鎖?

好吧,不能孤立地“為包含的列 C 插入新值”。如果您正在談論插入一個完整的新行,則情況與上述完全一樣。Range I-N用於測試範圍,然後X對新行進行鎖定。不需要Range X-X帶外掛的鎖。

也許您的意思是UPDATE,其中只有 C 列的值被更改。此處的行為取決於非聚集索引是否唯一,以及您定位的行是否存在:

  1. **唯一索引,行存在:**不需要範圍鎖。X在事務期間定位並鎖定目標行。
  2. **唯一索引,行不存在:**這是不存在數據的單例提取。鎖定目標索引鍵所在的範圍。這通常是Range S-S,但由於這是一條更新語句,Range S-U因此可以幫助避免轉換死鎖的常見原因。請注意,此處可能需要多個鎖。
  3. **非唯一索引,行存在:**這是一個範圍掃描查詢,用於定位要更新的行。範圍Range S-U像以前一樣被鎖定。更新目標行時,X會獲取該行的鎖。沒有Range S-X鎖,所以得到的組合鎖模式是Range X-X.
  4. 非唯一索引,行不存在: Range S-U鎖定被佔用並保持到事務結束。沒有行被更新,所以沒有排他鎖被佔用。

總體而言,包含索引鍵列的問題並不重要。SQL Server 中的可序列化隔離級別保證是通過根據需要鎖定索引鍵和範圍來確保正確性的。包含的列始終包含在其關聯的父鍵中。

範圍鎖僅在使用索引作為訪問方法時在行級別獲取。在其他情況下,SQL Server 使用更高粒度的“正常”(非範圍)鎖來遵守隔離級別。

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