具有 READ COMMITTED 隔离级别,已执行写操作的空闲事务将防止 vacuum 清理事务写入的表的死行。
对于由仍在进行中的事务写入的表来说,这一点很明显。 Here你可以找到一个很好的解释。
但我不清楚为什么此限制也会影响任何其他表。
例如:事务 T 启动并更新表 B,当 T 处于“idle in transaction”状态时,对表 A 执行 vacuum。在这种场景下,为什么A中的死行无法去除?
这是我做的:
# show default_transaction_isolation;
default_transaction_isolation
-------------------------------
read committed
(1 row)
# create table a (v int);
CREATE TABLE
# create table b (v int);
CREATE TABLE
# insert into a values (generate_series(1,1000));
INSERT 0 1000
此时我进行更新以生成新的 1000 个死行
# update a set v = v + 1;
UPDATE 1000
Vacuuming 将按预期删除它们:
# vacuum verbose a;
INFO: vacuuming "public.a"
INFO: "a": removed 1000 row versions in 5 pages
INFO: "a": found 1000 removable, 1000 nonremovable row versions in 9 out of 9 pages
DETAIL: 0 dead row versions cannot be removed yet.
There were 0 unused item pointers.
0 pages are entirely empty.
CPU 0.00s/0.00u sec elapsed 0.00 sec.
VACUUM
我现在开始在表 b 中写入事务 T:
# begin;
BEGIN
# insert into b values (generate_series(1,1000));
INSERT 0 1000
我在 T 之后开始的不同事务 T1 中再次生成更多死行:
# begin;
# update a set v = v + 1;
# commit;
在不同的事务中:
# vacuum verbose a;
INFO: vacuuming "public.a"
INFO: "a": found 0 removable, 2000 nonremovable row versions in 9 out of 9 pages
DETAIL: 1000 dead row versions cannot be removed yet.
There were 34 unused item pointers.
0 pages are entirely empty.
CPU 0.00s/0.00u sec elapsed 0.00 sec.
VACUUM
这是相关部分:详细信息:1000 个死行版本尚无法删除。
如果我提交事务 T 并再次执行 vacuum,我会按预期删除死行:
# vacuum verbose a;
INFO: vacuuming "public.a"
INFO: "a": removed 1000 row versions in 5 pages
INFO: "a": found 1000 removable, 1000 nonremovable row versions in 9 out of 9 pages
DETAIL: 0 dead row versions cannot be removed yet.
There were 34 unused item pointers.
0 pages are entirely empty.
CPU 0.00s/0.00u sec elapsed 0.00 sec.
VACUUM
最佳答案
通过 Twitter 跟进这个问题.
当前(至少达到 PostgreSQL 9.6)行为是:
在任何 表中执行写入操作的实时事务将防止清除由任何其他表 中第一个实时事务之后开始的已提交事务生成的死行。
从概念的角度来看,即使这个限制也不是必需的,它是当前算法实现的方式,以提高检查死行原因的性能。
关于postgresql - 为什么写在一个表中会阻止另一个表中的真空?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46099743/