PostgreSQL为什么认为两个可序列化事务之间存在冲突?

问题描述 投票:0回答:1

我正在尝试弄清楚PostgreSQL中可序列化的隔离级别如何工作。从理论上讲,根据PostgreSQL自己的文档,PostgreSQL应该足够聪明,以某种方式检测序列化冲突并自动回滚有问题的事务。但是,当我自己尝试使用可序列化隔离级别时,我偶然发现了许多误报,并开始怀疑自己对可序列化概念或PostgreSQL实现它的理解。您可以在下面找到此类误报的最简单示例之一:

create table mytab(
    class integer,
    value integer not null
);

create index mytab_class_idx on mytab (class);

insert into mytab (class, value) values (1, 10);
insert into mytab (class, value) values (1, 20);
insert into mytab (class, value) values (2, 100);
insert into mytab (class, value) values (2, 200);

表数据如下:

 class | value
-------+-------
     1 |    10
     1 |    20
     2 |   100
     2 |   200

然后我运行两个并发事务。代码中的Step n注释显示了我执行语句的顺序。遵循https://stackoverflow.com/a/42303225/3249257的建议,我明确禁用了顺序扫描以强制PostgreSQL使用索引:

SET enable_seqscan=off;

交易A:

begin; -- step 1
select sum(value) from mytab where class = 1; -- step 2
insert into mytab(class, value) values (3, 30); -- step 5
commit; -- step 7

交易B:

begin; -- step 3
select sum(value) from mytab where class = 2; -- step 4
insert into mytab(class, value) values (4, 300); -- step 6
commit; -- step 8

据我所知,这两项交易之间不应有任何冲突。他们不会碰到相同的行。但是,当我提交第二笔交易时,它失败并显示以下错误:

[40001] ERROR: could not serialize access due to read/write dependencies among transactions
Detail: Reason code: Canceled on identification as a pivot, during commit attempt.
Hint: The transaction might succeed if retried.

这里发生了什么?我对可序列化隔离级别的理解存在缺陷吗?答案https://stackoverflow.com/a/50809788/3249257中提到的PostgreSQL启发式方法是否失败?

我正在使用PostgreSQL 11.5 on x86_64-apple-darwin18.6.0, compiled by Apple LLVM version 10.0.1 (clang-1001.0.46.4), 64-bit

postgresql transactions serializable
1个回答
0
投票

这里的问题在于PostgreSQL使用谓词锁(SIReadLock)来确定并发事务之间是否存在冲突。如果在执行交易过程中运行以下查询,则会看到以下锁:

select relation::regclass, locktype, page, tuple, pid from pg_locks
where mode = 'SIReadLock';

在这种情况下,问题在于mytab_class_idx索引上的页面锁定。如果并发事务恰好为mytab_class_idx关系的同一页获取锁,则会发生序列化冲突。如果它们获取不同页面的锁,则它们都将成功提交。

如果像上面的问题那样没有足够的数据,则所有行的索引条目都将落在同一页上,然后不可避免地会发生序列化冲突。对于足够大的表,序列化冲突很少会发生,尽管不会那么罕见。

© www.soinside.com 2019 - 2024. All rights reserved.