2

具有 READ COMMITTED 隔离级别,已执行写操作的空闲事务将防止清理事务写入的表的死行。

对于由仍在进行中的事务写入的表来说,这一点很清楚。在这里你可以找到一个很好的解释。

但我不清楚为什么这个限制也会影响任何其他表。

例如:事务 T 启动并更新表 B,当 T 处于“事务中的空闲”状态时,对表 A 执行真空。在这种情况下,为什么无法删除 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 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
4

3 回答 3

1

通过Twitter 关注这个问题。

当前(至少到 PostgreSQL 9.6)行为是:

在任何表中执行写操作的实时事务将防止清除由在任何其他表中的第一个实时事务之后开始的已提交事务生成的死行。

即使从概念的角度来看,这个限制也不是必需的,它是当前算法是如何实现检查死行原因的性能的。

于 2017-09-11T11:18:26.290 回答
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)
于 2017-09-08T08:07:32.563 回答
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 位

于 2017-09-08T09:27:24.703 回答