SELECT 会像 V​​ACUUM 一样删除死行吗?

raf*_*fbm 9 postgresql select vacuum postgresql-11

我在摆弄VACUUM并注意到一些意想不到的行为,其中SELECT从表中ing 行似乎减少了VACUUM之后必须做的工作。

测试数据

注意:autovacuum 被禁用

CREATE TABLE numbers (num bigint);
ALTER TABLE numbers SET (
  autovacuum_enabled = 'f',
  toast.autovacuum_enabled = 'f'
);

INSERT INTO numbers SELECT generate_series(1, 5000);
Run Code Online (Sandbox Code Playgroud)

试验 1

现在我们对所有行运行更新,

UPDATE numbers SET num = 0;
Run Code Online (Sandbox Code Playgroud)

当我们跑步时,VACUUM (VERBOSE) numbers;我们得到,

INFO:  vacuuming "public.numbers"
INFO:  "numbers": removed 5000 row versions in 23 pages
INFO:  "numbers": found 5000 removable, 5000 nonremovable row versions in 45 out of 45 pages
DETAIL:  0 dead row versions cannot be removed yet, oldest xmin: 6585
There were 0 unused item pointers.
Run Code Online (Sandbox Code Playgroud)

试验 2

现在我们发出另一个UPDATE,但这次我们在SELECT后面添加一个,

UPDATE numbers SET num = 1;
SELECT * FROM numbers;
Run Code Online (Sandbox Code Playgroud)

当我们跑步时,VACUUM (VERBOSE) numbers;我们得到,

INFO:  vacuuming "public.numbers"
INFO:  "numbers": removed 56 row versions in 22 pages
INFO:  "numbers": found 56 removable, 5000 nonremovable row versions in 45 out of 45 pages
DETAIL:  0 dead row versions cannot be removed yet, oldest xmin: 6586
There were 56 unused item pointers.
Run Code Online (Sandbox Code Playgroud)

这里到底发生了什么?为什么我运行的第二个版本,在SELECT从它访问的页面中删除死元组之后,很像VACUUM

我在 macOS 10.14.5 上运行 Postgres 11.3。

Eva*_*oll 5

/r/PostgreSQL 上的这篇文章Laurenz Albe回答,似乎只对堆元组 (HOT) 更新负责。来自HOT 更新的描述src/backend/access/heap/README.HOT

实际上,当页面几乎已满(<10% 空闲)并且可以获得缓冲区清理锁时,在元组检索期间会发生空间回收。这意味着UPDATE, DELETE, 和SELECT可以触发空间回收,但通常不会触发空间回收,INSERT ... VALUES因为它不会检索行。

引用不在原始答案中,但其余部分是引用,

要支持或反驳这个理论,请运行以下查询:

SELECT n_tup_upd, n_tup_hot_upd
FROM pg_stat_user_tables
WHERE schemaname = 'public' AND relname = 'TABLE_NAME';
Run Code Online (Sandbox Code Playgroud)

如果n_tup_hot_upd大于零,我们有一个案例。