2012-04-20 4 views
19

私は、PostgreSQLのデッドロックについて少し読んでいます。UPDATE実行時のPostgreSQLのデッドロック

典型的なデッドロックの例は次のとおりです。私は、コードを変更

-- Transaction 1 
UPDATE customer SET ... WHERE id = 1 
UPDATE customer SET ... WHERE id = 2 

-- Transaction 2 
UPDATE customer SET ... WHERE id = 2 
UPDATE customer SET ... WHERE id = 1 

しかし、どのような場合には、次のように:

-- Transaction 1 
UPDATE customer SET ... WHERE id IN (1, 2) 

-- Transaction 2 
UPDATE customer SET ... WHERE id IN (1, 2) 

は、ここでデッドロックの可能性でしょうか?

本質的に私の質問は:は2番目のケースでは、PostgreSQLは行を1つずつロックするか、WHERE条件でカバーされるスコープ全体をロックしますか?

ありがとうございます!

答えて

28

PostgreSQLでは行が更新されるとロックされます。実際、実際には、各タプル(行のバージョン)にxminというシステムフィールドがあり、そのトランザクションがそのタプルの現在の挿入または更新によって)およびシステム・フィールドxmaxと呼ばれ、そのトランザクションが(更新または削除によって)そのタプルを満了したことを示します。データにアクセスすると、アクティブな「スナップショット」をこれらの値と照合して、各タプルをチェックしてトランザクションに表示されているかどうかを判断します。

UPDATEを実行していて、検索条件に一致するタプルが、スナップショットとアクティブなトランザクションのxmaxに表示されるxminを持つ場合、ブロックされ、そのトランザクションが完了するのを待っています。最初にタプルを更新したトランザクションがロールバックされると、トランザクションは起動して行を処理します。最初のトランザクションがコミットすると、トランザクションは起動し、現在のトランザクション分離レベルに応じてアクションを実行します。

明らかに、デッドロックは、この順序が異なる行の結果です。 RAMには行レベルのロックはありませんが、これはすべての行に対して同時に取得できますが、行が同じ順序で更新される場合は循環ロックを使用できません。残念ながら、提案されているIN(1, 2)構文は、それを保証するものではありません。別のセッションでは異なる原価計算係数がアクティブになる可能性があります。バックグラウンドの「分析」タスクは、1つのプランの生成と他のプランの生成の間にテーブルの統計を変更する可能性があります。すでに進行中のディスクに参加し、ディスクI/Oを減らすために「ループ・アラウンド」します。

一度に1つずつ、アプリケーションコード内で、またはカーソルを使用して更新を行う場合は、デッドロックではなく単純なブロックのみが使用されます。ただし、リレーショナル・データベースではシリアライゼーション障害が発生しやすく、SQLSTATEに基づいてトランザクションを認識し、最初からトランザクション全体を自動的に再試行するフレームワークを介してリレーショナル・データベースにアクセスすることが最善です。 PostgreSQLでは、直列化の失敗は常に40001または40P01のSQLSTATEを持ちます。

http://www.postgresql.org/docs/current/interactive/mvcc-intro.html

+0

ありがとうございます! 上記の例はデッドロックを引き起こす可能性があります(私たちは両方のトランザクションで行が処理される順序がわからないため)? – vyakhir

+0

デッドロックが発生する可能性はありますが、それはまれです。最初の例(明示的に異なる注文を選択する)とは対照的に、どこに共通するのでしょうか。デッドロックを排除するには、テーブルを更新するすべてのトランザクションの期間中、テーブルレベルの適切な強度のロックを取ることによって、デッドロックを排除することができます。ただし、その治癒は、病気よりも悪い可能性があります。詳細については、私が参照したドキュメントのセクションを参照してください。 – kgrittn

+0

しかし、行が更新された後、PostgreSQLのリリースロックは解除されますが、UPDATE文全体はまだ終了していませんか? つまり、 のようなステートメントがある場合は、UPDATE ... WHERE id IN(1,2,3,4,5) postgresqlの更新後、たとえばid = 1の行とid = 2、それは行id = 1をリリースしますか?はいの場合は、必要に応じて行をどのようにロールバックするのでしょうか? – vyakhir

関連する問題