25

〜50K行のデータベーステーブルがあり、各行は実行する必要があるジョブを表しています。DBからジョブを抽出し、ジョブを実行して結果をdbに戻すプログラムがあります。(このシステムは現在稼働中です)

ここで、複数の処理タスクがジョブを実行できるようにしたいのですが、タスクが 2 回実行されないようにします (これが他の問題を引き起こすのではないというパフォーマンス上の懸念から)。アクセスはストアド プロシージャを介して行われるため、私の現在の方法は、ストアド プロシージャを次のようなものに置き換えることです。

update tbl 
set owner = connection_id() 
where available and owner is null limit 1;

select stuff 
from tbl 
where owner = connection_id();

ところで; ワーカーのタスクは、ジョブの取得と結果の送信の間の接続を切断する可能性があります。また、その部分を台無しにしない限り、DBがボトルネックに近づくことさえないと思います(1分あたり〜5ジョブ)

これに問題はありますか?これを行うより良い方法はありますか?

注: 「IPC アンチパターンとしてのデータベース」は、ここでは少しだけ適切です。

  1. 私はIPCを行っていません(行を生成するプロセスはありません。現在、それらはすべてすでに存在しています)
  2. そのアンチパターンについて説明されている主な不満は、プロセスがメッセージを待機するときにDBに不要な負荷がかかることです(私の場合、メッセージがない場合、すべてが完了するとすべてがシャットダウンする可能性があります)
4

6 に答える 6

14

これが私が過去にうまく使ったものです:

MsgQueueテーブルスキーマ

MsgId identity -- NOT NULL
MsgTypeCode varchar(20) -- NOT NULL  
SourceCode varchar(20)  -- process inserting the message -- NULLable  
State char(1) -- 'N'ew if queued, 'A'(ctive) if processing, 'C'ompleted, default 'N' -- NOT NULL 
CreateTime datetime -- default GETDATE() -- NOT NULL  
Msg varchar(255) -- NULLable  

あなたのメッセージタイプはあなたが期待するものです-挿入するプロセスと読み取るプロセスの間の契約に準拠し、XMLまたは他の表現の選択で構造化されたメッセージ(JSONは場合によっては便利です実例)。

次に、0からnのプロセスが挿入され、0からnのプロセスがメッセージの読み取りと処理を行うことができます。通常、各読み取りプロセスは単一のメッセージタイプを処理します。プロセスタイプの複数のインスタンスを実行して、負荷分散を行うことができます。

リーダーは1つのメッセージをプルし、メッセージの処理中に状態を「A」アクティブに変更します。完了すると、状態が「完了」に変わります。監査証跡を保持するかどうかに応じて、メッセージを削除するかどうかを指定できます。State ='N'のメッセージは、MsgType / Timestampの順序でプルされるため、MsgType + State+CreateTimeにインデックスがあります。

バリエーション:
「E」エラーの状態。
Readerプロセスコードの列。
状態遷移のタイムスタンプ。

これにより、説明しているような多くのことを実行するための、優れた、スケーラブルで、目に見える、シンプルなメカニズムが提供されます。データベースの基本を理解している場合、それはかなり確実で拡張可能です。


コメントからのコード:

CREATE PROCEDURE GetMessage @MsgType VARCHAR(8) ) 
AS 
DECLARE @MsgId INT 

BEGIN TRAN 

SELECT TOP 1 @MsgId = MsgId 
FROM MsgQueue 
WHERE MessageType = @pMessageType AND State = 'N' 
ORDER BY CreateTime


IF @MsgId IS NOT NULL 
BEGIN 

UPDATE MsgQueue 
SET State = 'A' 
WHERE MsgId = @MsgId 

SELECT MsgId, Msg 
FROM MsgQueue 
WHERE MsgId = @MsgId  
END 
ELSE 
BEGIN 
SELECT MsgId = NULL, Msg = NULL 
END 

COMMIT TRAN
于 2008-11-17T23:31:54.090 に答える
0

可能性のあるテクノロジの変更として、MSMQ などの使用を検討することもできます。

各ジョブ/スレッドは、メッセージング キューにクエリを実行して、新しいジョブが利用可能かどうかを確認できます。メッセージを読み取る行為はそれをスタックから削除するため、1 つのジョブ/スレッドのみがメッセージを取得することが保証されます。

もちろん、これは Microsoft プラットフォームで作業していることを前提としています。

于 2008-11-17T23:55:19.503 に答える
0

所有されていないときに owner = null を持つ代わりに、代わりに偽の nobody レコードに設定する必要があります。null を検索してもインデックスは制限されないため、テーブル スキャンが発生する可能性があります。(これはオラクル用です。SQL サーバーは異なる場合があります)

于 2008-11-17T23:13:34.830 に答える
-6

「データベースを IPC として」アンチパターンを実装しようとしています。ソフトウェアを適切に再設計することを検討する必要がある理由を理解するには、それを調べてください。

于 2008-11-17T23:06:28.183 に答える