[pgsql-jp: 40166] 子テーブルの2回目の更新でデッドロック

HIRATSUKA Sadao sh2 @ pop01.odn.ne.jp
2010年 2月 13日 (土) 11:38:41 JST


こんにちは、平塚といいます。

外部キー制約のあるテーブルで、子テーブルの2回目の更新で
デッドロックが発生するという事象に悩まされています。
PostgreSQL 8.4.2です。

create table parent (k int primary key, d varchar(10));
create table child (k int primary key, f int, d varchar(10),
    constraint child_fk1 foreign key (f) references parent (k));

insert into parent values (1, 'a');
insert into parent values (2, 'b');

insert into child values (11, 1, 'aa');
insert into child values (12, 2, 'bb');

client1> begin;
client1> update parent set d = 'a2' where k = 1;

client2> begin;
client2> update parent set d = 'b2' where k = 2;
client2> update parent set d = 'a3' where k = 1; -- blocked

client1> update child set d = 'bb2' where k = 12; -- ok
client1> update child set d = 'bb3' where k = 12; -- deadlock

ERROR:  deadlock detected
DETAIL:  Process 307 waits for ShareLock on transaction 80443;
blocked by process 311.
Process 311 waits for ShareLock on transaction 80442;
blocked by process 307.
HINT:  See server log for query details.
CONTEXT:  SQL statement "SELECT 1 FROM ONLY "public"."parent" x
WHERE "k" OPERATOR(pg_catalog.=) $1 FOR SHARE OF x"

1回目の「update child set d = 'bb2' where k = 12」は通るのに、
同じSQLをもう1回投げるとデッドロックになるのが不思議です。

プログラム自体はリトライするように直しているところですが、
これはどういう仕組みで発生しているのでしょうか。


処理の流れを単純化すると、
以下のシーケンスで2回目の更新がブロックされています。

client1> begin;
client1> update parent set d = 'a2' where k = 1;

client2> begin;
client2> update child set d = 'aa2' where k = 11; -- ok
client2> update child set d = 'aa3' where k = 11; -- blocked


以下の記事は拝見しました。8.1以降なら大丈夫かと思ったのですが…。
http://itpro.nikkeibp.co.jp/article/COLUMN/20050904/220557/?ST=oss&P=3

よろしくお願いいたします。

-- 
平塚貞夫 <sh2 @ pop01.odn.ne.jp>


pgsql-jp メーリングリストの案内