5

シリアライズ可能なトランザクション分離レベルは、他のトランザクションの選択ステートメントと競合するトランザクションのテーブルへの挿入をブロックすることで、ファントム読み取りの問題を回避します。例で理解しようとしていますが、選択ステートメントのフィルターが競合していない場合でも挿入をブロックします。なぜそのように振る舞うかについての説明をいただければ幸いです。

テーブル スクリプト

CREATE TABLE [dbo].[dummy](
    [firstname] [char](20) NULL,
    [lastname] [char](20) NULL
) ON [PRIMARY]

GO

セッション - 1

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
begin tran
select * from dummy where firstname = 'abc'

セッション - 2

insert into dummy values('lmn', 'lmn') -- Why this blocks?
4

2 に答える 2

11

テスト シナリオの最初の問題は、テーブルに有用なインデックスがないことです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')
于 2010-07-11T23:57:04.560 に答える
0

http://msdn.microsoft.com/en-us/library/ms173763.aspxから

SERIALIZABLE 以下を指定します。

ステートメントは、他のトランザクションによって変更されたがまだコミットされていないデータを読み取ることはできません。

現在のトランザクションが完了するまで、他のトランザクションは現在のトランザクションによって読み取られたデータを変更できません。

私が理解しているように、SELECT が実行されているトランザクションが完了していないため、挿入はブロックされます。

于 2010-07-09T15:48:49.483 に答える