バグはありませんし、あなたが何かを誤解しているとは思いません。パズルのいくつかのピースが欠けているだけです。
外部キーは、行レベルのロックを使用して内部的に実装されます。 Postgres 8.1から9.2まで、参照テーブル(apples
)を更新するたびに この場合)、SELECT FOR SHARE
を実行するクエリが実行されます。 参照されるテーブル(trees
)。そのため、SELECT FOR UPDATE
最初のトランザクションで、SELECT FOR SHARE
をブロックします 2番目のトランザクションの参照整合性。これが2番目のコマンドでブロックを引き起こす原因です。
今、私はあなたが叫ぶのを聞きます。最初のコマンドではなく、2番目のコマンドでブロックされるのはなぜですか?説明は本当に簡単です。これは、内部のSELECT FOR SHARE
をスキップする単純な最適化があるためです。 キーが変更されていないとき。ただし、これは単純化されており、タプルを2回更新しても、元の値を追跡するのが難しいため、この最適化は実行されません。したがって、閉塞。
また、なぜこれが9.2までだと言ったのか不思議に思うかもしれません--- 9.3とは何ですか?主な違いは、9.3ではSELECT FOR KEY SHARE
を使用することです。 、これは新しい、より軽いロックレベルです。それはより良い並行性を可能にします。 9.3で例を試し、SELECT FOR UPDATE
も変更した場合 SELECT FOR NO KEY UPDATE
(これはSELECT FOR UPDATE
よりも軽いモードです つまり、タプルを更新する可能性がありますが、主キーを変更せず、削除しないことを約束します)、ブロックされないことがわかります。 (また、参照されている行でUPDATEを試すことができます。主キーを変更しないと、ブロックされません。)
この9.3のものは、本当に http://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=0ac5ad5134f2769ccbaefec73844f8504c4d6182 そして、それはかなりクールなハックだったと思います(そのようなことを気にするなら、コミットメッセージにはもう少し詳細があります)。ただし、9.3.4より前のバージョンは使用しないでください。パッチが非常に複雑であるため、いくつかの重大なバグが見過ごされ、最近修正されたばかりです。