web-dev-qa-db-ja.com

SQL Serverのキー範囲RangeI-Nロックの互換性

documentation は、RangeI-Nロック(範囲を挿入、nullリソースロック、新しいキーをインデックスに挿入する前に範囲をテストするために使用)がそれ自体と互換性があることを示しています(互換性マトリックスを参照)。 1つのトランザクションが特定のキーのRangeI-Nロックを取得したとしても、別のトランザクションもそのようなロックを取得できます。

さらに以下では、それは言う

トランザクション内に値を挿入する場合、挿入操作を実行するトランザクションの間、値が該当する範囲をロックする必要はありません。トランザクションの最後まで挿入されたキー値をロックすることで、直列化を維持できます。たとえば、次のINSERTステートメントがあるとします。

INSERT mytable VALUES( 'Dan');

RangeI-Nモードのキー範囲ロックは、Davidという名前に対応するインデックスエントリに配置され、範囲をテストします。ロックが許可されると、Danが挿入され、値Danに排他(X)ロックが設定されます。 RangeI-Nモードのキー範囲ロックは、範囲をテストするためにのみ必要であり、挿入操作を実行するトランザクションの間は保持されません。他のトランザクションは、挿入された値Danの前後に値を挿入または削除できます。ただし、値Danの読み取り、挿入、または削除を試みるトランザクションは、挿入トランザクションがコミットまたはロールバックするまでロックされます。

別の引用 source -Microsoft SQL Server 2008 Internals:Transactions and Concurrency:

たとえば、SQL ServerがSerializable分離を使用してセッション内のキー間の範囲に挿入しようとすると、RangeIn-Nullロックが取得されます。このタイプのロックは、通常非常に一時的なものであるため、あまり見られません。正しい挿入位置が見つかるまで保持され、その後ロックはXロックに変換されます。

私の理解では、このタイプのロックは、新しく挿入されたキーを配置する必要がある範囲を特定するプロセス中です(これが「範囲のテスト」の意味だと思います)。これが発生すると、ロックが解除され、新しいキーが挿入され、Xロックが設定されます。

ただし、2つのRangeI-Nロックが互いに互換性があると言われている理由はわかりません。トランザクションAとBの両方が新しいキーを範囲に挿入することを望んでおり、トランザクションAが最初に挿入を実行するため、両方のキーが同じキーにRangeI-Nロックを配置する場合、Bによって決定されたキー挿入の場所はすでに正しくない可能性があります。範囲が変更されました(Aに新しい値が挿入されました)。誰かがそれを説明できますか?

9
user4205580

私の理解では、このタイプのロックは、新しく挿入されたキーを配置する必要がある範囲を特定するプロセス中です(これが「範囲のテスト」の意味だと思います)。これが発生すると、ロックが解除され、新しいキーが挿入され、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 locking footprint

キー範囲を保護するために、データベースエンジンはRangeS-Sロックでこの範囲のすべてのキーをロックします。さらに、範囲の横のキーがロックされています(これは一意でないインデックスに必要ですが、エンジンは一意のインデックスにもそれを行います)。この場合、キーは1、2、9、および10に対応するリソースにロックされます(以前に行われたクエリの結果による)。

テーブルへの非同時挿入

INSERT INTO T (K)
VALUES (3);

次のロックフットプリントの結果

INSERT locking footprint

キー3はテーブルに存在しないため、データベースエンジンは、キー9に対応するリソース(30b7763ed433)RangeI-Nロックを要求します。瞬間。 RangeI-Nを取得すると、実行中の互換性のないシリアル化可能なアクティビティがないため、エンジンが続行し、キーに対応するリソース(98ec012aa510)Xロックを取得します。 3.次に、実際の挿入が行われ、ロックが解放されます。 RangeI-Nロックの解放がないことに注意してください。

上記のSELECTINSERTを同時に実行すると、INSERTは、トランザクションで実行されたシリアル化可能なSELECTがアクティブになるまで待機します

SELECT and INSERT concurrency

RangeI-NRangeS-Sと互換性がないためです。トランザクションが実行されるとすぐにSELECTが終了しますINSERTが続行します。

これが「範囲のテスト」の意味です。


ただし、2つのRangeI-Nロックが互いに互換性があると言われている理由はわかりません。

RangeI-Nは、キー範囲への同時挿入を許可するため、ロックの互換性は良好です。

私たちがやっていると想像してください

INSERT INTO T (K)
VALUES (4);

そして

INSERT INTO T (K)
VALUES (6);

同時に。

ある時点で、両方のステートメントが、キー9に対応するリソース(30b7763ed433)RangeI-Nを取得することがあります。ただし、同時実行性はキーのXおよびページラッチによってさらに。

4
i-one