それで、Postgresql での外部キー制約の処理について混乱しています。(バージョン 8.4.4、その価値はあります)。
いくつかのテーブルがあり、以下に穏やかに匿名化されています。
device:
(id, blah, blah, blah, blah, blah x 50)…
primary key on id
whooooole bunch of other junk
device_foo:
(id, device_id, left, right)
Foreign key (device_id) references device(id) on delete cascade;
primary key on id
btree index on 'left' and 'right'
そこで、いくつかのクエリを実行するために 2 つのデータベース ウィンドウを用意しました。
db1> begin; lock table device in exclusive mode;
db2> begin; update device_foo set left = left + 1;
db2 接続がブロックされます。
device_stuff の「左」列の更新がデバイス テーブルのアクティビティの影響を受けるというのは奇妙に思えます。しかし、そうです。実際、db1 に戻ると、次のようになります。
db1> select * from device_stuff for update;
*** deadlock occurs ***
pgsql ログには次の内容があります。
blah blah blah deadlock blah.
CONTEXT: SQL statement "SELECT 1 FROM ONLY "public"."device" x WHERE "id" OPERATOR(pg_catalog.=) $1 FOR SHARE OF X: update device_foo set left = left + 1;
私には 2 つの問題があると思います。1 つ目は、この種のロックが発生する正確なメカニズムを理解していないことです。pg_locks をクエリして、ステートメントが呼び出すロックの種類を確認するための便利なクエリがいくつかありますが、update device_foo
コマンドを単独で実行したときに、この特定の種類のロックを観察することはできませんでした。(おそらく、私は何か間違ったことをしているのかもしれません。) また、外部キー制約チェックのロック取得動作に関するドキュメントも見つかりません。私が持っているのはログメッセージだけです。このことから、行を変更すると、外部キーが設定されているすべてのテーブルで更新ロックが取得されると推測できますか?
2番目の問題は、そのようにならないようにする方法を見つけたいということです。実際のアプリケーションで時々デッドロックが発生します。device_foo
デバイス テーブルで大きなロックを取得することなく、すべての行に影響を与える大きな更新ステートメントを実行できるようにしたいと考えています。(テーブルでは多くのアクセスが行われており、device
取得するのにコストのかかるロックのようなものです。)