为什么在 table 中写入以防止在另一个中出现真空?
why writes in a table prevent vacuums in another?
具有 READ COMMITTED 隔离级别,已执行写操作的空闲事务将防止真空清理事务写入的 table 的死行。
对于 table 由仍在进行中的交易写入的数据来说,这一点很明显。 Here你可以找到一个很好的解释。
但我不清楚为什么这个限制也会影响 any 其他 tables.
例如:事务 T 启动并更新 table B,在 T 处于 "idle in transaction" 状态时为 table 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
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
我现在开始事务 T 写入 table b:
# 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
无法重现:
第一个会话脚本:
-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)
在保持打开的事务之后启动的事务中再次生成死行很重要。
我已经能够使用以下版本重现该问题:
PostgreSQL 9.3.19 on x86_64-unknown-linux-gnu,由 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 位'
通过 Twitter 关注这个问题。
当前(至少达到 PostgreSQL 9.6)行为是:
在 any table 中执行写入操作的实时事务将防止清除由在 any 中的第一个实时事务之后开始的已提交事务生成的死行其他 table.
从概念的角度来看,即使这个限制也不是必需的,但当前算法是如何实现的,以提高检查死行的性能。
具有 READ COMMITTED 隔离级别,已执行写操作的空闲事务将防止真空清理事务写入的 table 的死行。
对于 table 由仍在进行中的交易写入的数据来说,这一点很明显。 Here你可以找到一个很好的解释。
但我不清楚为什么这个限制也会影响 any 其他 tables.
例如:事务 T 启动并更新 table B,在 T 处于 "idle in transaction" 状态时为 table 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
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
我现在开始事务 T 写入 table b:
# 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
无法重现:
第一个会话脚本:
-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)
在保持打开的事务之后启动的事务中再次生成死行很重要。
我已经能够使用以下版本重现该问题:
PostgreSQL 9.3.19 on x86_64-unknown-linux-gnu,由 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 位'
通过 Twitter 关注这个问题。
当前(至少达到 PostgreSQL 9.6)行为是:
在 any table 中执行写入操作的实时事务将防止清除由在 any 中的第一个实时事务之后开始的已提交事务生成的死行其他 table.
从概念的角度来看,即使这个限制也不是必需的,但当前算法是如何实现的,以提高检查死行的性能。