所以,我对 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'
所以我开始使用两个数据库窗口来运行一些查询。
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;
我想我有两个问题:第一个是我不了解发生这种锁定的确切机制。update device_foo
我有几个有用的查询来查询 pg_locks 以查看语句调用的锁类型,但是当我单独运行命令时,我无法观察到这种特定类型的锁。(不过,也许我做错了什么。)我也找不到任何关于外键约束检查的锁定获取行为的文档。我只有一条日志消息。我是否可以从中推断出对行的任何更改都将在它所针对的所有表上获得更新锁?
第二个问题是我想找到一些方法让它不会像那样发生。我在实际应用程序中偶尔会出现死锁。我希望能够运行影响所有行的大更新语句,device_foo
而无需在设备表上获得大锁。(表中有很多访问权限device
,而且这是一种昂贵的锁。)