0

ERPシステムに注文を提供するPostgreSQL9.2.2データベースがあります。データベーステーブルには、他のレコードの中で顧客が追加されたかどうかを示すブール列が含まれています。私が使用するコードは、データベースから行を抽出し、それらを一度に1つずつERPシステムに送信します(シングルスレッド)。私のコードはこの点で完全に機能します。ただし、過去1年間で、ボリュームはマルチスレッドソリューションを必要とするほど大きくなりました。

add_customer列は、顧客が正常に追加された後にのみ更新されるため、MVCCモードが機能するとは思いません。デフォルトのMVCCモードでは、同じ行が同時に処理され、Webサービス呼び出しが重複する可能性があります。私が避けたいのは、ERPシステムへの重複したWebサービス呼び出しです。これはかなり重い可能性があるためですが、確かに私はMVCCやPostgreSQLが提供する他のモードの専門家ではありません。

私の質問は次のとおりです。1つのselectステートメントで返された1つまたは一連の行が、別々のスレッドでデータベースへの他のクエリから除外されるようにするにはどうすればよいですか?

4

2 に答える 2

0

行が何らかの方法で処理されているという事実を記録する必要があります。また、それらを処理済みとしてマークする同時試行に対処し、ERPシステムに送信することで障害を処理する必要があります。

SELECT ... FOR UPDATEは、行のセットを取得し、同時にそれらを更新に対してロックするのに役立つ場合があります。1つのアプローチは、各スレッドがターゲット行を選択し、そのIDを「処理」テーブルに追加してから、added_customerを更新するのと同じトランザクションでそれを削除することです。

スレッドが候補行をフェッチしない場合、または挿入に失敗した場合は、一時的にスリープして再試行する必要があります。何かがひどくうまくいかない場合は、検査/修正できる行を「処理」テーブルに残しておく必要があります。

もちろん、他のオプションは、候補行のセットを取得し、ERPと通信するそれぞれに個別のプロセス/スレッドを生成することです。これにより、ERPへの複数のチャネルを許可しながら、データベースがシングルスレッドでフェッチし続けます。

于 2013-01-11T14:52:45.560 に答える
0

テーブルに列を追加できuser_is_proccesedます。レコードを更新するバックエンドのプロセスIDを保持できます。

次に、小さなシリアル化可能なトランザクションを使用して、 「処理のためuser_is_proccesedに行をロックする」に設定します。

何かのようなもの:

START TRANSACTION  ISOLATION LEVEL SERIALIZABLE;

UPDATE user_table
SET user_is_proccesed = pg_backend_pid()
WHERE <some condition>
  AND user_is_proccesed IS NULL; -- no one is proccesing it now

COMMIT;

ここで重要なのはSERIALIZABLE、1つのトランザクションだけでレコードを正常に更新できることです(他のすべての同時SERIALIZABLE更新はで失敗しますERROR: could not serialize access due to concurrent update)。

于 2013-01-11T15:13:00.180 に答える