Ami*_*ron 8 postgresql locking transactions
我们遇到了PostgreSQL 9.0.12锁定机制的问题.
这是我们重现问题的最小代码:
脚本
Transaction 1 Transaction 2
BEGIN BEGIN
...... select trees for update;
update apples;
--passes
update apples;
-- stuck!
Run Code Online (Sandbox Code Playgroud)
重现代码:如果你想在你的PostgreSQL中尝试它 - 这是一个你可以复制/粘贴的代码.
我有一个以下数据库架构:
CREATE TABLE trees (
id integer primary key
);
create table apples (
id integer primary key,
tree_id integer references trees(id)
);
insert into trees values(1);
insert into apples values(1,1);
Run Code Online (Sandbox Code Playgroud)
打开两个psql shell:
在shell 1上:
BEGIN;
SELECT id FROM trees WHERE id = 1 FOR UPDATE;
Run Code Online (Sandbox Code Playgroud)
在shell 2上:
BEGIN;
UPDATE apples SET id = id WHERE id = 1;
UPDATE apples SET id = id WHERE id = 1;
Run Code Online (Sandbox Code Playgroud)
苹果的第二次更新将卡住,似乎shell 2的进程在shell 1的事务上完成.
relname |transactionid|procpid|mode |substr | age |procpid
-----------+-------------+-------+------------------+------------------------------------------+----------------+-------
| | 4911 | ExclusiveLock | <IDLE> in transaction | 00:05:42.718051|4911
| 190839904 | 4911 | ExclusiveLock | <IDLE> in transaction | 00:05:42.718051|4911
trees | | 4911 | RowShareLock | <IDLE> in transaction | 00:05:42.718051|4911
| | 5111 | ExclusiveLock | UPDATE apples SET id = id WHERE id = 1; | 00:05:21.67203 |5111
| 190839905 | 5111 | ExclusiveLock | UPDATE apples SET id = id WHERE id = 1; | 00:05:21.67203 |5111
apples_pkey| | 5111 | RowExclusiveLock | UPDATE apples SET id = id WHERE id = 1; | 00:05:21.67203 |5111
apples | | 5111 | RowExclusiveLock | UPDATE apples SET id = id WHERE id = 1; | 00:05:21.67203 |5111
trees | | 5111 | RowShareLock | UPDATE apples SET id = id WHERE id = 1; | 00:05:21.67203 |5111
trees | | 5111 | ShareLock | UPDATE apples SET id = id WHERE id = 1; | 00:05:21.67203 |5111
| | 2369 | ExclusiveLock | <IDLE> in transaction | 00:00:00.199268|2369
| | 2369 | ExclusiveLock | <IDLE> in transaction | 00:00:00.199268|2369
| | 5226 | ExclusiveLock | select pg_class.relname,pg_locks.transac | 00:00:00 |5226
Run Code Online (Sandbox Code Playgroud)
我们误解了什么或者是postgres中的错误吗?
没有错误,我认为你不会误解任何事情; 你只是错过了几个难题.
外键使用行级锁定在内部实现; 从Postgres 8.1开始直到9.2,无论何时更新引用表(apples在本例中),都会触发SELECT FOR SHARE对引用的表(trees)执行的查询.因此,SELECT FOR UPDATE在第一个事务中阻止SELECT FOR SHARE第二个事务的引用完整性.这是导致第二个命令中的块的原因.
现在我听到你喊道,"等等!为什么它阻止第二个命令而不是第一个?解释很简单,真的 - 这只是因为有一个简单的优化,SELECT FOR SHARE当密钥没有被修改时会跳过内部.但是,这很简单,如果您第二次更新元组,则此优化不会触发,因为它更难以跟踪原始值.因此阻塞.
你可能也想知道为什么我说这是9.2--什么是9.3?主要区别在于它使用的是9.3 SELECT FOR KEY SHARE,这是一个新的,更轻的锁定级别; 它允许更好的并发性.如果你在9.3中尝试你的例子并且也改变了SELECT FOR UPDATEto 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之前的版本,因为该补丁非常复杂,以至于一些严重的错误被忽视,我们最近才修复.
| 归档时间: |
|
| 查看次数: |
708 次 |
| 最近记录: |