8

これが表です(簡略化):

                                       テーブル「public.link」
    コラム| タイプ| 修飾子                     
--------------- + ----------------------------- + ---- -----------------------------------------------
 id | 整数| nullではないデフォルトnextval('link_id_seq' :: regclass)
 page_id | 整数|
 Placed_at | タイムゾーンなしのタイムスタンプ| デフォルトのnow()
インデックス:
    "link_pkey" PRIMARY KEY、btree(id)
    "link_page_id_index" btree(page_id)
外部キーの制約:
    "link_page_id_foreign_key"外部キー(page_id)参照page(id)ON UPDATE RESTRICT ON DELETE RESTRICT

そしてここにクエリがあります(簡略化されています):

UPDATEリンクSETpage_id=?、placed_at = now()
WHERE id IN(SELECT id FROM link ...)AND page_id IS NOT NULL

デッドロックメッセージ:

エラー:デッドロックが検出されました
  詳細:プロセス5822は、トランザクション19705でShareLockを待機します。プロセス5821によってブロックされました。
プロセス5821は、トランザクション19706でShareLockを待機します。プロセス5822によってブロックされました。
  ヒント:クエリの詳細については、サーバーログを参照してください。

複数のプロセスによって並行して実行されるそのクエリは、どのようにしてデッドロックにつながる可能性がありますか?
ありがとう!

4

2 に答える 2

16

セッションAはID10、2、30、4を更新しようとし、セッションBは40、30、20、10で試行します

どちらも更新の準備ができてそれぞれの行をロックしようとし、Aは10を取得して30を待機し、Bは30を取得して10を待機します。デッドロック。

基本的な問題は、同時トランザクションで同じID(の一部)を更新しようとしていることです。

データベースの構造と何をしようとしているのかを正確に知らなければ、最善の解決策を提案することは困難です。通常、異なるバックエンドが同じ行を更新しないようにするか、タイムアウトを減らして、ランダムに一時停止した後に再試行します。

于 2012-10-12T11:56:45.853 に答える
1

ほとんどの場合、行間の循環待機が更新されるためにデッドロックが発生するため、デッドロックを解決する場合は、更新する行の順序を使用するだけです。

UPDATE link SET page_id = ?, placed_at = now() 
WHERE id IN ( SELECT id FROM link ... order by page_id ) AND page_id IS NOT NULL
于 2016-01-06T21:13:33.313 に答える