テスト シナリオの最初の問題は、テーブルに有用なインデックスがないことですfirstname
。2 つ目は、テーブルが空であることです。
BOLのキー範囲ロックから
キー範囲のロックが発生する前に、次の条件を満たす必要があります。
トランザクション分離レベルは に設定する必要がありますSERIALIZABLE
。
クエリ プロセッサは、範囲フィルター述語を実装するためにインデックスを使用する必要があります。たとえばWHERE
、ステートメントの句は、次のSELECT
述語で範囲条件を確立できますColumnX BETWEEN N'AAA' AND
N'CZZ'
。キー範囲ロックは、ColumnX がインデックス キーでカバーされている場合にのみ取得できます。
ロックを取得する適切なインデックスがないRangeS-S
ため、シリアライズ可能なセマンティクスを保証するために、SQL Server はテーブル全体をロックする必要があります。
以下のようにテーブルの名の列にクラスタ化インデックスを追加して実験を繰り返すと……
CREATE CLUSTERED INDEX [IX_FirstName] ON [dbo].[dummy] ([firstname] ASC)
...まだブロックされていることがわかります。
適切なインデックスが存在し、クエリを満たすためにインデックスがシークされていることを実行計画が示しているという事実にもかかわらず。
次のコマンドを実行すると、その理由を確認できます
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRAN
SELECT *
FROM dummy
WHERE firstname = 'abc'
SELECT resource_type,
resource_description,
request_mode
FROM sys.dm_tran_locks
WHERE request_session_id = @@SPID
COMMIT
戻り値
+---------------+----------------------+--------------+
| resource_type | resource_description | request_mode |
+---------------+----------------------+--------------+
| DATABASE | | S |
| OBJECT | | IS |
| PAGE | 1:198 | IS |
| KEY | (ffffffffffff) | RangeS-S |
+---------------+----------------------+--------------+
SQL Server は、クエリで指定した正確な範囲に対して範囲ロックを解除するだけではありません。
一致するキーがある場合、一意のインデックスの等値述語の場合、任意のタイプの範囲ロックではなく、通常のロックが使用されます。
一意でないシーク述語の場合、範囲内のすべての一致するキーと、範囲の末尾にある「次の」キー (またはffffffffffff
「次の」キーが存在しない場合は無限を表す) のロックが解除されます。削除された「ゴースト」レコードでさえ、この範囲キー ロックで使用できます。
ここで説明されているように、一意または非一意のインデックスの等価述語について
キーが存在しない場合、一意のインデックスと一意でないインデックスの両方について、「次の」キーで「範囲」ロックが取得されます。「次の」キーが存在しない場合、「無限」の値に対して範囲ロックが行われます。
そのため、空のテーブルでSELECT
も、インデックス全体をロックすることになります。abc
また、以前に と の間に行を挿入しておく必要がありますlmn
。そうすれば、挿入は成功します。
insert into dummy values('def', 'def')