2011-11-01 13 views
5

私が欲しいへ:SQL Selectテーブルから行と更新し、同じ行が

    フラグ=
  1. 0は、これらの値を用いて第2のテーブルの上にいくつかの作業を行う処理用のテーブルから
  2. 選択N行 N行
  3. 更新これらのN行セットフラグ= 1

は、私は一緒にこの同じ仕事をして並列処理を持っている、と私はすべてが一意の行に仕事を得ることを確実にしたいです。どうすればそれを保証できますか?

答えて

5

私は(タグのために)SQL Server上で動作していると仮定します。そうでなければ、私の答えは当てはまりません。 ロックだけでは十分ではありません。データベースレコードロックを使用すると、SqLサーバーはロックされた行にアクセスしようとしている他のプロセスをブロックし、実際には一度に1つの行しか処理しません。 解決策は、行ロックとREADPASTヒントを組み合わせて、他の誰かによってロックされた行をスキップすることです。ここでは、各プロセスが何をすべきかです:

  1. は、処理のために次のロック解除された行を選択し、それが
  2. 行と終了トランザクションに仕事に
  3. 更新を行うロック

select top 1 id, ... from TheTable with (updlock, readpast) where flag = 0

//do the work now

update TheTable set flag = 1 where id=<previously retrieved id>

ロックされていない次の行を選択してロックする操作がアトミックなので、ほかの誰も同じ行を選択できないことを保証します。

+0

READPASTヒントは、良い記事です。http://www.mssqltips.com/sqlservertip/1257/processing-data-queue-in-sql-server-with-readpast-and-updlock/ – newbie

+0

SQL 2008クエリのREADPAST HINTとともにOUTPUT句を使用して、キュー操作を単一の文に結合することができます.http://www.sqlservercentral.com/articles/Queue+processing/69653/ – newbie

+0

@newbieはい、使用できますメッセージをロックおよび取得し、単一のクエリで処理されたことをマークします。しかし、私は単一のメッセージ処理のパフォーマンスを比較してきましたが、2つのクエリ(最初に選択してから更新)に比べて利益はありません。実際には、OUTPUTクエリを使用すると、マルチスレッドスループットが少し低下しました。多分、バッチ処理ではOutput節が速くなりますが、単一のメッセージではそうではありません。 – nightwatch

0

1つの方法は、マスタープログラムが子スレッドにセグメントを渡すことです。

もう1つの方法は、テーブルをロックし、フラグが0のローのCEIL(N/#processes)を取得し、フラグを2に更新してロックを解除します。その後、ロックを取得してから次のプロセスが続行され、flag = 2のため、これらの行は取得されません。

テーブルをロックする方法は2つあります。すべてをロックするか、制限付きでSELECT ... FOR UPDATEを実行します(行が多すぎないようにする)。参照:SELECT FOR UPDATE with SQL Server

フラグを2に設定するよりも、フラグをprocess_idに設定する方が効果的です。次に、すべての行を更新して番号を配布し、プロセスを動作させ、それぞれが自分の行だけをチェックするだけです。

関連する問題