2011-06-17 64 views
3

hereのようなSQLテーブルを使用してキューシステムをセットアップする必要があります。ことで、この選択した後、私は、ので、私は私が最初の表においてROWLOCK及び第二にUPDLOCKを使用していORDER BYとWITH(ROWLOCK、UPDLOCK、READPAST)

BEGIN TRANSACTION 

CREATE TABLE #Temp (ID INT, SOMEFIELD INT) 

INSERT INTO #Temp SELECT TOP (@Something) TableA.ID, TableB.SomeField FROM TableA WITH (ROWLOCK, READPAST) INNER JOIN TableB WITH (UPDLOCK, READPAST) WHERE Condition1 

INSERT INTO #Temp SELECT TOP (@Something) TableA.ID, TableB.SomeField FROM TableA WITH (ROWLOCK, READPAST) INNER JOIN TableB WITH (UPDLOCK, READPAST) WHERE Condition2 

(...) 

UPDATE TableB SET SomeField = 1 FROM TableB WITH (ROWLOCK, READPAST) WHERE ID IN (SELECT ID FROM #Temp) 

COMMIT TRANSACTION 

を使用しているストアドプロシージャ内、異なるcriteraによってキューに入れられたアイテムをフィルタリングする必要があるためTableBのみ更新しますが、これらの行は他の並行クエリによってTableAに更新されないようにする必要があります。上記のSELECTのいずれかにORDER BY句を挿入する必要があるまで、すべてがうまくいくので、非常に特定のIDだけが選択されます(私は本当にこれをしなければなりません)。何が起こるか:

1)ORDER BYを指定しないと、2つの同時実行が必要に応じて実行され、異なる結果と重複しない結果が返されます。しかし、これらの正確な結果はすべてのSELECTステートメントの範囲外だったので、彼らは私が望む結果を返しません。

2)ORDER BYと2回の同時実行を使用すると、最初の結果のみが結果を返します。 2番目のものは何も返しません。

WITH (ROWLOCK, READPAST)ORDER BYで動作するこれらの種類のクエリでは、注文に使用しているフィールドにインデックスを作成する必要があることを思い出してください。私はそれを試みたが、私は同じ結果を得た。どうすればこの問題を回避できますか?

編集:たとえば、私はフィールド(テストID INT、値INT)と値をテーブルTestTable持っている場合は、 "(1,1)、(2,2)、..." と "同時" 実行

BEGIN TRANSACTION 

SELECT TOP 2 TestID FROM TestTable WITH (UPDLOCK, READPAST) 

WAITFOR DELAY '00:00:05' 

COMMIT TRANSACTION 

最初の実行は行(1,2)を返し、2番目の行は応答として(3,4)を返します。しかし、実行すると

BEGIN TRANSACTION 

SELECT TOP 2 TestID FROM TestTable WITH (UPDLOCK, READPAST) ORDER BY VALUE ASC 

WAITFOR DELAY '00:00:05' 

COMMIT TRANSACTION 

最初のものは(1,2)を返し、2番目のものは何も返しません。どうしてこれなの?!

答えて

4

  • ORDER BYでのSELECTは、ROWLOCKせずに、インデックスなしTOP 2を動作するための中間/スキャンソートのテーブルロックを持つことになりますので、2回目のセッションは、全体をスキップ予想通りテーブルがREADPASTのため

  • ORDER BYのないSELECTは、挿入順(純粋な一致、暗示された順序はありません)の順序で行われます。これらの2行がロックされているため、2番目のセッションはロックされていない次の行にスキップされます。

SQL Serverはロックを可能な限り細かく維持しようとしますが、スキャンはテーブルロックを意味します。さて、これは通常の違いをすることはないだろう(それは共有読み取りロックだろう)しかし、あなたは、あなたがこれらの

  • 3ヒントの両方をだから、排他的にロックテーブル

    を意味UPDLOCKあまりにも必要になりましたSELECTクエリ(ROWLOCK、UPDLOCK、READPAST)を使用して、粒度、分離、並行性を制御します。
    ROWLOCKのみを使用すると、すべての行で排他的ロックがスキャン/ソートされます。

  • インデックスがValueにあります。SELECTを効率的にするためにINCLUDE TestIDです。索引のみが並行性を修正する可能性がありますが、それは保証されません。私はすべての3つのロックヒント

    を持ってSQL Server Process Queue Race Conditionに(コメントで)私の答えにリンクされている以前の質問の一つで