1

次の状況で、Postgresql 9.2 サーバーでまれにデッドロックが発生することがわかりました。

T1 がバッチ操作を開始します。

UPDATE BB bb SET status = 'PROCESSING', chunk_id = 0 WHERE bb.status ='PENDING' 
AND bb.bulk_id = 1 AND bb.user_id IN (SELECT user_id FROM BB WHERE bulk_id = 1 
AND chunk_id IS NULL AND status ='PENDING' LIMIT 2000)

T1 が数百ミリ秒程度 (BB には数百万行あります) 後にコミットすると、複数のスレッドが新しいトランザクション (スレッドごとに 1 つのトランザクション) を開始します。クエリ:

選択する場合:

SELECT *, RANK() as rno OVER(ORDER BY user_id) FROM BB WHERE status = 'PROCESSING' AND bulk_id = 1 and rno = $1

そして更新:

UPDATE BB set datetime=$1, status='DONE', message_id=$2 WHERE bulk_id=1 AND user_id=$3

(user_id、bulk_id には UNIQUE 制約があります)。

外部の状況の問題により、別のトランザクション T2 は、T1 がコミットされたほぼ直後に T1 で同じクエリを実行します (アイテムが「PROCESSING」としてマークされる最初のバッチ操作)。

UPDATE BB bb SET status = 'PROCESSING', chunk_id = 0 WHERE bb.status ='PENDING' 
AND bb.bulk_id = 1 AND bb.user_id IN (SELECT user_id FROM BB WHERE bulk_id = 1 
AND chunk_id IS NULL AND status ='PENDING' LIMIT 2000)

ただし、これらのアイテムは「PROCESSING」としてマークされていますが、このクエリは、ワーカースレッドからの一部の更新 (前述のようにバッチで行われます) でデッドロックします。私の理解では、これは、使用する READ_COMMITTED 分離レベル (デフォルト) では発生しないはずです。ワーカー スレッドはコミット後に実行されるため、T1 がコミットしたことは確かです。

編集:私が片付けなければならないことの1つは、T2がT1の後、コミットする前に開始することです。ただし、同じ行で取得した write_exclusive タプル ロックSELECT for UPDATE(上記のクエリのいずれにも影響されない) のため、バッチ更新クエリを実行する前に T1 がコミットするのを待ちます。

4

1 に答える 1

0

T1 が数百ミリ秒程度 (BB には数百万行あります) 後にコミットすると、複数のスレッドが新しいトランザクション (スレッドごとに 1 つのトランザクション) を開始します。クエリ:

これは、並行性の問題だと思います。1 つのトランザクションで行を読み取ってワーカー プロセスに渡し、戻ってきたときにバッチで更新する方がはるかに良いと思います。あなたの根本的な問題は、これらの行が不確実な状態で効果的に機能していること、トランザクション中に行を保持していることなどです。ロールバックなどを個別に処理する必要があるため、ロックは実際の問題です。

その解決策が不可能な場合は、別のロック テーブルを使用します。この場合、各スレッドは個別にスピンアップし、ロック テーブルをロックし、一連の行を要求し、レコードをロック テーブルに挿入し、コミットします。このようにして、各 1 つのスレッドがレコードを要求しました。その後、彼らは自分のレコード セットで作業したり、更新したりできます。古いロックを定期的にクリアするプロセスが必要になる場合があります。

本質的に、あなたの問題は、行が状態 A -> 処理中 -> 状態 B になり、ロールバックされる可能性があることです。他のスレッドは、どの行がどのスレッドによって処理されているかを知る方法がないため、レコードを安全に割り当てることはできません。1 つのオプションは、モデルを次のように変更することです。

状態 A -> 要求された状態 -> 処理中 -> 状態 B. ただし、行が効果的に割り当てられ、スレッドがどの行が互いに割り当てられているかを認識できるようにする何らかの方法が必要です。

于 2013-09-01T03:33:52.130 に答える