最近、私は想像していた問題に対処する必要がありました。処理される行が数百万を超えるデータベーステーブルと、さまざまなマシンやスレッドで実行されるさまざまなプロセッサどのように安全に各プロセッサインスタンスが相互に干渉することなく仕事の塊(例えば100アイテム)を得ることができるか?仕事の塊の取得
私が一度にチャンクを取得しているのはパフォーマンス上の理由からです。私は各アイテムのデータベースに行きたくありません。
最近、私は想像していた問題に対処する必要がありました。処理される行が数百万を超えるデータベーステーブルと、さまざまなマシンやスレッドで実行されるさまざまなプロセッサどのように安全に各プロセッサインスタンスが相互に干渉することなく仕事の塊(例えば100アイテム)を得ることができるか?仕事の塊の取得
私が一度にチャンクを取得しているのはパフォーマンス上の理由からです。私は各アイテムのデータベースに行きたくありません。
いくつかのアプローチがあります - 各プロセッサにトークンを関連付けることができ、次の[n]個の利用可能なアイテムに対してそのトークンを設定するSPROCを持つことができます。おそらく何かのように:
(ノートでは - 、適切な分離レベルを必要とします。おそらく、シリアライズ:SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
)
UPDATE TOP (1000) WORK
SET [Owner] = @processor, Expiry = @expiry
OUTPUT INSERTED.Id -- etc
WHERE [Owner] IS NULL
あなたはまた、タイムアウト(@expiry
)にしたいと思います(TSQLを修正するために編集しました)プロセッサがダウンしたときに作業を失うことはありません。 Expiry
を過ぎているものについてオーナーをクリアする作業も必要です。
MSMQやActiveMQなどのミドルウェアキューイングソリューションを使用して、消費者が作業を削除(またはマーク)したり、ミドルウェアキューイングソリューションを使用したりする特別なテーブルを作成することができます。
ミドルウェアには固有の問題がありますので、可能であれば、私はできるだけ小さくしてください。可能であればidを使用して、従業員が残りの情報を単独で取得できるようにしてくださいデータベースの残りの部分では、キューテーブルを長時間ロックしないでください)。
この表を一定間隔で記入し、プロセッサーが必要なものを上から把握できるようにします。 SQLテーブル・キュー上の
関連質問:
Working out the SQL to query a priority queue table
キューイングミドルウェア上関連した質問:
Building a high performance and automatically backupped queue
使用しているデータベースサーバーについては言及していませんが、いくつかのオプションがあります。
MySQLには、更新される行の数を制限するSQL99のINSERT
の拡張機能が含まれています。各ワーカーに一意のトークンを割り当てたり、行数を更新したり、クエリを実行してそのワーカーのバッチを取得することができます。 MarcはUPDATE TOP
構文を使用しましたが、データベースサーバーは指定しませんでした。
もう1つのオプションは、ロックに使用するテーブルを指定することです。データに同じテーブルを使用しないでください。読み込みのためにロックしたくないからです。あなたのロックテーブルはたぶん1行しか必要とせず、次のIDが必要です。作業者がテーブルをロックし、現在のIDを取得し、バッチサイズが何であれ増分し、テーブルを更新してロックを解除します。次に、それはデータテーブルを照会し、それを予約した行を引き出すことができます。このオプションは、データテーブルが単調に増加するIDを持っていることを前提としており、作業者が死んだり、そうでなければバッチを完了できない場合、フォールトトレラントではありません。この質問に非常に似
は:SQL Server Process Queue Race Condition
あなたは与えられたprocessoridに100行を割り当てるために、クエリを実行します。これらのロックヒントを使用すると、並行処理の意味で「安全」です。これはSET文が不要な単一のSQL文です。
これは、他の質問から取られる:
UPDATE TOP (100)
foo
SET
ProcessorID = @PROCID
FROM
OrderTable foo WITH (ROWLOCK, READPAST, UPDLOCK)
WHERE
ProcessorID = 0 --Or whatever unassigned is
おかげで、マルク。私はあなたがアップデートでTOPを使うことができるとは思わなかった。 UPDATEのようなものを試していました[テーブル] SET [所有者] = @プロセッサWHERE ID IN(SELECT ROW_NUMBER()(オーダーID順)ROWNUMBER、ID FROM [表] WHERE [オーナー] ROWNUMBER <= 100)、SQL-99に準拠しているようです。 –
その複雑さが増すと、SET ROWCOUNT 100はもっと簡単になります... –