Problem with foreign keys (performance and deadlocks)

Поиск
Список
Период
Сортировка
От Brian Walker
Тема Problem with foreign keys (performance and deadlocks)
Дата
Msg-id 200212101047160506.0086BCF5@mail.mcsdallas.com
обсуждение исходный текст
Ответы Re: Problem with foreign keys (performance and deadlocks)  (Stephan Szabo <sszabo@megazone23.bigpanda.com>)
Список pgsql-bugs
Sorry for this being so long but I want to describe this as thoroughly as p=
ossible.

I am having two problems with foreign keys.  One is a performance problem a=
nd the other is a deadlock problem but they  are related to the same root c=
ause.  I am running PostgreSQL 7.3 (the released version).

I have isolated it down to a simple test:

Given the following database:

create table names (
    id integer not null,
    name text not null,
    primary key (id)
);

create table orders (
    id integer not null,
    nameid integer,
    description text,
    primary key (id)
);
alter table orders add constraint oname foreign key(nameid) references name=
s(id);

insert into names values (1,'bob');
insert into names values (2,'fred');
insert into names values (3,'sam');

insert into orders values (1,1,'bob1');
insert into orders values (2,1,'bob2');
insert into orders values (3,1,'bob3');
insert into orders values (4,2,'fred1');
insert into orders values (5,3,'sam1');

To reproduce the bug, start psql on the database in two different shells.

In shell A:

begin;
update orders set description=3D'bob1-1' where id=3D1;


In shell B:

begin;
update orders set description=3D'bob2-1' where id=3D2;


The update in shell B will blocuntilll you do a "commit;" or "rollback;" in=
 shell A.  This blocking should not occur.

The problem is that the update in shell A causes a

SELECT 1 FROM ONLY "public"."names" x WHERE "id" =3D $1 FOR UPDATE OF x

statement to be generated internally as part of the foreign key checking.  =
For shell A this works fine but when shell B executes this line it blocks u=
ntil the transaction in shell A does a commit or rollback.

The purpose of this SELECT seems to be two-fold:
 1. To make sure that row in the target table exists.
2. To make sure that the row does not get deleted or that column in that ro=
w does not get changed until the commit  happens because other transactions=
 cannot see the changes until the commit happens.

As a test I went into "backend/utils/adt/ri_triggers.c" and removed the "FO=
R UPDATE OF X" from the foreign key checks  and the concurrency issues disa=
ppeared.  This still make check 1 happen but removed the safety net of chec=
k 2.

The "FOR UPDATE OF X" seems to grab a lock that cannot be shared so the sec=
ond foreign key select must wait until the  first one releases.  Is there a=
 weaker lock that can applied to the foreign key check in ri_triggers.c?  I=
s a new type  of lock "FOR FKEY OF X" required?

This really drags down our system when we get alot of traffic.  It also als=
o causes deadlocks.

DEADLOCK
--------

The example is a very simple case but in my application where I have more t=
ables and multiple foreign keys I run into  deadlocks.

In the simplest case I have multiple "information" tables that are the targ=
ets of foreign keys.  I have 2 "data"  tables that have foreign keys into t=
he information tables.  If I am inserting/updating rows in tables "data1" a=
nd  "data2".

Here is an example I made up to (hopefully) make this clear:

create table names (
    id integer not null,
    name text not null,
    primary key (id)
);

create table billaddr (
    id integer not null,
    address text not null,
    primary key (id)
);

create table shipaddr (
    id integer not null,
    address text not null,
    primary key (id)
);

create table phone_orders (
    id integer not null,
    nameid integer,
    billid integer,
    shipid integer,
    description text,
    primary key (id)
);
alter table phone_orders add constraint poname  foreign key(nameid) referen=
ces names(id);
alter table phone_orders add constraint pobaddr foreign key(billid) referen=
ces billaddr(id);
alter table phone_orders add constraint posaddr foreign key(shipid) referen=
ces shipaddr(id);

create table web_orders (
    id integer not null,
    nameid integer,
    billid integer,
    shipid integer,
    description text,
    primary key (id)
);
alter table web_orders add constraint woname  foreign key(nameid) reference=
s names(id);
alter table web_orders add constraint wobaddr foreign key(billid) reference=
s billaddr(id);
alter table web_orders add constraint wosaddr foreign key(shipid) reference=
s shipaddr(id);

insert into names values (1,'bob');
insert into names values (2,'fred');
insert into names values (3,'sam');

insert into billaddr values (1,'123 main st');
insert into billaddr values (2,'456 minor ave');

insert into shipaddr values (1,'789 major ct');
insert into shipaddr values (2,'912 losers lane');

insert into phone_orders values (1,1,1,1,'phone order 1');
insert into phone_orders values (2,2,2,2,'phone order 2');

insert into web_orders values (1,1,1,1,'web order 1');
insert into web_orders values (2,2,2,2,'web order 2');


Once again start psql on the database in two different shells.

In shell A:

begin;
update phone_orders set description=3D'phone order 1-1' where id=3D1;


In shell B:

begin;
update web_orders set description=3D'web order 1-1' where id=3D1;

If the PostgreSQL server acquires the foreign key locks in a different orde=
r on the web-orders and phone_orders tables  then you will get a deadlock. =
 When I ran this exact case I did not see this but I have seen it when runn=
ing my  application.  I reorganized by schema to try to get the locks to be=
 acquired in the same order all the time but I  could not get it to work.  =
Even if I could get this to work it would not solve the performance issue.


I saw a discussion on this from March:

http://archives.postgresql.org/pgsql-hackers/2002-03/msg01156.php

These does not seem to be a resolution to this yet.

Are there any plans to fix this soon?  This is a serious problem for us.

Thanks

Brian Walker

В списке pgsql-bugs по дате отправления:

Предыдущее
От: Tom Lane
Дата:
Сообщение: Re: Bug #843: pg_clog files problem
Следующее
От: Mauro Goncalves de Oliveria
Дата:
Сообщение: ...