具有READ COMMITTED隔离级别,执行写入操作的空闲事务将阻止vacuum清除事务所写入的表的死行。
对于仍在进行中的事务编写的表格,这一点很清楚。 Here你可以找到一个很好的解释。
但我不清楚为什么此限制也会影响任何其他表。
例如:事务T启动并更新表B,对表A执行真空,而T在事务中处于空闲状态"州。在这种情况下,为什么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
吸尘将按预期删除它们:
# 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
答案 0 :(得分:0)
无法重现:
第一个会话脚本:
-bash-4.2$ cat prim.sql
create table a (v int);
create table b (v int);
insert into a values (generate_series(1,1000));
update a set v = v + 1;
vacuum verbose a;
begin;
insert into b values (generate_series(1,1000));
select pg_sleep(9);
select e'I\'m still open transaction'::text prim;
第二次会话并检查状态:
-bash-4.2$ cat 1.sh
(sleep 3; psql t -c "vacuum verbose a;") &
(sleep 5; psql t -c "select state,query from pg_stat_activity where state != 'idle' and pid <> pg_backend_pid()") &
psql t -f prim.sql
并运行:
-bash-4.2$ bash 1.sh
CREATE TABLE
CREATE TABLE
INSERT 0 1000
UPDATE 1000
psql:prim.sql:5: INFO: vacuuming "public.a"
psql:prim.sql:5: INFO: "a": removed 1000 row versions in 5 pages
psql:prim.sql:5: 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
BEGIN
INSERT 0 1000
INFO: vacuuming "public.a"
INFO: "a": found 0 removable, 1000 nonremovable row versions in 9 out of 9 pages
DETAIL: 0 dead row versions cannot be removed yet.
There were 1000 unused item pointers.
0 pages are entirely empty.
CPU 0.00s/0.00u sec elapsed 0.00 sec.
VACUUM
state | query
--------+---------------------
active | select pg_sleep(9);
(1 row)
pg_sleep
----------
(1 row)
prim
----------------------------
I'm still open transaction
(1 row)
正如您所看到的那样,第一次会话在不同会话中的真空之前和之后都处于活动状态。
我试过的版本是:
t=# select version();
version
--------------------------------------------------------------------------------------------------------------
PostgreSQL 9.3.14 on x86_64-redhat-linux-gnu, compiled by gcc (GCC) 4.8.3 20140911 (Red Hat 4.8.3-9), 64-bit
(1 row)
答案 1 :(得分:0)
在事务保持打开之后启动的事务中再次生成死行非常重要。
我已经能够使用以下版本重现该问题:
x86_64-unknown-linux-gnu上的PostgreSQL 9.3.19,由gcc编译(Ubuntu 4.8.4-2ubuntu1~14.04.3)4.8.4,64位
x86_64-pc-linux-gnu上的PostgreSQL 9.5.9,由gcc编译(Ubuntu 4.8.4-2ubuntu1~14.04.3)4.8.4,64位&#39;
答案 2 :(得分:0)
通过Twitter提出此问题。
当前(至少取决于PostgreSQL 9.6)的行为是:
在任何表中执行写入操作的实时事务将阻止清除在任何其他表中首次实时事务后启动的提交事务生成的死行。
从概念的角度来看,即使这个限制也不是必需的,它是如何在检查死行原因的情况下实现当前算法的。