3

トランザクションを開始し、Table1 にレコードを挿入し、実行時間の長い (最大 30 秒) Web サービスを呼び出すプロセスがあります。Web サービスの呼び出しが失敗した場合、挿入はロールバックされます (これが望ましいことです)。これは挿入の例です(実際には複数のテーブルへの複数の挿入ですが、この質問のために単純化しています):

INSERT INTO Table1 (UserId, StatusTypeId) VALUES (@UserId, 1)

次のように、最初のステップから Table1 をクエリする 2 番目のプロセスがあります。

SELECT TOP 1 * FROM Table1 WHERE StatusTypeId=2

次に、ユーザーのその行を更新します。プロセス 1 の実行中は、Table1 がロックされるため、プロセス 1 が完了するまでプロセス 2 は完了しません。これは、プロセス 1 が Web サービスの呼び出しを完了するまでに長い遅延が発生するため、問題になります。

プロセス 1 は 1 の StatusTypeId のみを挿入し、Table1 に挿入する唯一の操作でもあります。プロセス 2 は StatusTypeId = 2 に対してのみクエリを実行します。プロセス 2 に、Table1 への挿入を無視するが、選択した行をロックするように指示したいと思います。プロセス 2 のデフォルトの分離レベルでは待機が多すぎますが、IsolationLevel.ReadUncommitted がダーティ データの読み取りを許可しすぎているのではないかと心配しています。プロセス 2 を実行している 2 人のユーザーが誤って同じ行を取得することは望ましくありません。

挿入された行を無視すると言う ReadUncommitted 以外に使用する別の IsolationLevel はありますが、選択した行が選択されていることを確認してください。

4

2 に答える 2

4

SELECTが挿入によってブロックされていることに関しては、適切なインデックスを提供することでこれを回避できるはずです。

テストテーブル。

CREATE TABLE Table1
(
UserId INT PRIMARY KEY,
StatusTypeId INT,
AnotherColumn varchar(50)
)
insert into Table1
SELECT number, (LEN(type)%2)+1, newid()
FROM master.dbo.spt_values
where type='p'

クエリウィンドウ1

BEGIN TRAN
INSERT INTO Table1 (UserId, StatusTypeId) VALUES (5000, 1)
WAITFOR DELAY '00:01';
ROLLBACK

クエリウィンドウ2(ブロック)

SELECT TOP 1 * 
FROM Table1 
WHERE StatusTypeId=2 
ORDER BY AnotherColumn

ただし、インデックスを追加した後でテストを再試行しても、ブロックされませんCREATE NONCLUSTERED INDEX ix ON Table1 (StatusTypeId,AnotherColumn)

行のロックに関してProcess 2は、次を使用できます(READPASTヒントを使用するとProcess 2、一方が他方をブロックするのではなく、2つの同時トランザクションが異なる行の処理を開始できます)。RemusRusanuによるこの記事が関連していると思うかもしれません

BEGIN TRAN

SELECT TOP 1 * 
FROM Table1  WITH (UPDLOCK, READPAST)
WHERE StatusTypeId=2
ORDER BY AnotherColumn

/*
Rest of Process Two's code here
*/
COMMIT
于 2010-08-04T12:51:25.177 に答える
4

編集:質問を読み直した後、いずれかのロックはinsert、インデックスに問題がある可能性がありますselectREAD COMMITTED

ただし、コメントと残りの質問から、一度に1つのトランザクションのみが行を読み取れるようにする必要があるようです。これは、分離レベルが防止するものではありません。

彼らは防ぐ

  • Dirty Read- ロールバックされる可能性のあるトランザクションでコミットされていないデータを読み取る - で発生し、でREAD UNCOMMITTED防止されるREAD COMMITTEDREPEATABLE READSERIALIZABLE

  • Non Repeatable Reads- コミットされていないトランザクションで読み取り中に行が更新されます。つまり、特定の行の同じ読み取りがトランザクションで 2 回発生し、異なる結果が生成される可能性があります。 - で発生しREAD UNCOMMITTEDますREAD COMMITTED。で防止REPEATABLE READSERIALIZABLE

  • phantom rows- コミットされていないトランザクションで読み取り中に行が挿入または削除された。つまり、複数の行の同じ読み取りがトランザクションで 2 回発生し、行が追加または欠落して異なる結果が生成される可能性がある - で発生READ UNCOMMITTED、、、READ COMMITTEDREPEATABLE READ防止SERIALIZABLE
于 2010-08-04T11:02:47.457 に答える