
PostgreSQL有一个可选但是被推荐的特性autovacuum(从8.1版本加入),它的目的是自动执行VACUUM和ANALYZE 命令,回收被表示为删除状态记录的空间。
对表元组的UPDATE或DELETE操作并未立即删除旧版本的数据,表中的旧元组只是被标识为删除状态,并未立即释放空间。
这种处理对于多版本并发控制(MVCC)是必要的,如果一个元组的版本仍有可能被其它事务看到,那么久不能删除元组的该版本。
当事务提交后,过期元组版本将对事务不再有效,因而其占据的空间必须回收以供其他新元组使用,以避免磁盘空间被消耗殆尽。

src/include/storage/itemid.h
typedef ItemIdData *ItemId;
/*
* lp_flags has these possible states. An UNUSED line pointer is available
* for immediate re-use, the other states are not.
*/
#define LP_UNUSED 0 未使用 /* unused (should always have lp_len=0) */
#define LP_NORMAL 1 已使用/* used (should always have lp_len>0) */
#define LP_REDIRECT 2 HOT重定向/* HOT redirect (should have lp_len=0) */
#define LP_DEAD 3 死元祖/* dead, may or may not have storage */
恢复或重用被已更新或已删除行所占用的磁盘空间。 更新被PostgreSQL查询规划器使用的数据统计信息。 更新可见性映射,可以加速索引的扫描。 保护老旧数据不会由于事务ID回卷或多事务ID回卷而丢失。

从指定的表中依次处理每一张表。
获取表上的ShareUpdateExclusiveLock锁,此锁允许其他事物对该表进行读取。
扫描表中所有的页面,以获取所有的死元组,并在必要时冻结旧的元组。
删除指向相应死元组的索引元组。
对表的每个页面执行步骤6和7中的操作。
删除死元组,并重新分配页面中的活元组。
更新目标表对应的FSM与VM。
如果最后一个页面没有任何元组,则截断最后一页。
更新与目标表清理过程相关的统计数据和系统视图。
更新与清理过程相关的统计数据和系统视图。
如果可能,移除CLOG中非必要的文件与页面。
vacuumdb [connection-option...] [option...] [ --table | -t table [( column [,...] )] ] ... [dbname]
vacuumdb [connection-option...] [option...] --all | -a
postgres@bogon-> vacuumdb -h 127.0.0.1 -p 5432 -F -f -z -v -j 3 -d postgres -U postgres
-j 3 并行度等于3
VACUUM [ ( option [, ...] ) ] [ table_and_columns [, ...] ]
VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] [ ANALYZE ] [ table_and_columns [, ...] ]
FULL [ boolean ]
FREEZE [ boolean ]
VERBOSE [ boolean ]
ANALYZE [ boolean ]
DISABLE_PAGE_SKIPPING [ boolean ]
SKIP_LOCKED [ boolean ]
INDEX_CLEANUP [ boolean ]
TRUNCATE [ boolean ]
PARALLEL integer PostgreSQL13 新增的 PARALLEL 参数
table_name [ ( column_name [, ...] ) ]
初始化,VACUUM正在准备开始扫描堆。这个阶段应该很简短。
扫描堆, VACUUM正在扫描堆。如果需要,它将会对每个页面进行修建以及碎片整理,并且可能会执行冻结动作。heap_blks_scanned列可以用来监控扫描的进度。
清理索引,VACUUM当前正在清理索引。如果一个表拥有索引,那么每次清理时这个阶段会在堆扫描完成后至少发生一次。如果maintenance_work_mem不足以存放找到的死亡元组,则每次清理时会多次清理索引。
清理堆,VACUUM当前正在清理堆。清理堆与扫描堆不是同一个概念,清理堆发生在每一次清理索引的实例之后。如果heap_blks_scanned小于heap_blks_total,系统将在这个阶段完成之后回去扫描堆;否则,系统将在这个阶段完成后开始清理索引。
清除索引,VACUUM当前正在清除索引。这个阶段发生在堆被完全扫描并且对堆和索引的所有清理都已经完成以后。
截断堆,VACUUM正在截断堆,以便把关系尾部的空页面返还给操作系统。这个阶段发生在清除完索引之后。
执行最后的清除,VACUUM在执行最终的清除。在这个阶段中,VACUUM将清理空闲空间映射、更新pg_class中的统计信息并且将统计信息报告给统计收集器。当这个阶段完成时,VACUUM也就结束了。
track_counts:是否开启统计信息收集功能。
autovacuum:是否启动系统自动清理功能,默认值为on。
autovacuum_max_workers:设置系统自动清理工作进程的最大数量。
autovacuum_naptime:设置两次系统自动清理操作之间的间隔时间。
autovacuum_vacuum_cost_limit:声明将在自动VACUUM操作里使用的开销限制数值。
autovacuum_vacuum_cost_delay :声明如果超过了上面的开销限制,则需要延迟清理的时间。
autovacuum_freeze_max_age:设置需要强制对数据库进行清理的XID上限值。
autovacuum_multixact_freeze_max_age:设置需要强制对数据库进行清理的multi XID上限值。因为AutoVacuum依赖于统计信息,所以只有track_counts=on 且 autovacuum=on 时,PostgreSQL才启动autovacuum launcher 进程。autovacuum launcher 进程会周期性地创建autovacuum worker 进程,最多能够创建autovacuum_max_workers个autovacuum worker 进程。
vacuum_multixact_failsafe_age
vacuum_failsafe_ag
analyze [verbose] [table[(column[,..])]]
verbose:显示处理的进度,以及表的一些统计信息
table:要分析的表名,如果不指定,则对整个数据库中的所有表作分析
column:要分析的特定字段的名字默认是分析所有字段
analyze 命令 会在表上加读锁
统计信息记录在哪里
用于进行查询计划选择的统计信息记录在系统表内
pg_statistic 记录值的分布率
pg_class 记录行数和页面数

autovacuum_vacuum_threshold = 50 #阈值
autovacuum_vacuum_scale_factor = 0.2 #比例因子
一是调小大表的比例因子
二是放弃比例因子,调大阈值
vacuum_cost_page_hit = 1 #如果页面是从shared_buffers读取的,则计为1。
vacuum_cost_page_miss = 10 #如果在shared_buffers找不到并且需要从操作系统中读取,则计为10(它 可能仍然从RAM提供,但我们不知道)
vacuum_cost_page_dirty = 20 #当清理修改一个之前干净的块时需要花费的估计代价,它表示再次把脏块刷 出到磁盘所需要的额外I/O,默认值为20
当update,delete的tuples数量超过 autovacuum_vacuum_scale_factor * table_size + autovacuum_vacuum_threshold
指定表上事务的最大年龄配置参数autovacuum_freeze_max_age,默认为2亿,达到这个阀值将触发 autovacuum进程,从而避免 wraparound。
postgres=# create table test(id int,info text);
CREATE TABLE
postgres=# insert into test select generate_series(1,1000000),md5(random()::text);
INSERT 0 1000000
postgres=# create index idx_test on test(id);
CREATE INDEX
postgres=# create index idx_test_info on test(info);
CREATE INDEX
postgres=# vacuum (parallel 4) test;
VACUUM
Time: 64.417 ms
postgres=# vacuum (verbose true) test;
INFO: vacuuming "public.test"
INFO: launched 1 parallel vacuum worker for index cleanup (planned: 1)
INFO: "test": found 0 removable, 40 nonremovable row versions in 1 out of 8334 pages
DETAIL: 0 dead row versions cannot be removed yet, oldest xmin: 491
There were 0 unused item identifiers.
Skipped 0 pages due to buffer pins, 0 frozen pages.
0 pages are entirely empty.
CPU: user: 0.00 s, system: 0.03 s, elapsed: 0.04 s.
INFO: vacuuming "pg_toast.pg_toast_16384"
INFO: "pg_toast_16384": found 0 removable, 0 nonremovable row versions in 0 out of 0 pages
DETAIL: 0 dead row versions cannot be removed yet, oldest xmin: 491
There were 0 unused item identifiers.
Skipped 0 pages due to buffer pins, 0 frozen pages.
0 pages are entirely empty.
CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.
postgres=# \timing on
Timing is on.
postgres=# vacuum test;
VACUUM
Time: 6388.633 ms (00:06.389)
postgres=#
postgres@bogon-> vacuumdb -h 127.0.0.1 -p 5432 -F -f -z -v -j 3 -d postgres -U postgres
-j 3 并行度等于3
[root@bogon ~]# ps -ef |grep postgres
postgres 6438 46335 0 22:59 pts/1 00:00:00 vacuumdb -h 127.0.0.1 -p 5432 -F -f -z -v -j 3 -d postgres -U postgres
postgres 6442 86102 99 22:59 ? 00:00:01 postgres: postgres postgres 127.0.0.1(41236) VACUUM
postgres 6443 86102 37 22:59 ? 00:00:00 postgres: postgres postgres 127.0.0.1(41238) VACUUM
postgres 6444 86102 39 22:59 ? 00:00:00 postgres: postgres postgres 127.0.0.1(41240) VACUUM
postgres 6446 86102 0 22:59 ? 00:00:00 postgres: parallel worker for PID 6442
postgres 86102 1 0 08:21 ? 00:00:01 /opt/pgsql12/bin/postgres
postgres 86103 86102 0 08:21 ? 00:00:00 postgres: logger
postgres 86105 86102 0 08:21 ? 00:00:00 postgres: checkpointer
postgres 86106 86102 0 08:21 ? 00:00:15 postgres: background writer
postgres 86107 86102 0 08:21 ? 00:00:24 postgres: walwriter
postgres 86108 86102 0 08:21 ? 00:00:00 postgres: autovacuum launcher
postgres 86109 86102 0 08:21 ? 00:00:01 postgres: stats collector
postgres 86110 86102 0 08:21 ? 00:00:00 postgres: logical replication launcher
postgres 86113 86102 0 08:21 ? 00:00:12 postgres: postgres postgres [local] idle
执行了3个vacuum
postgres 6442 86102 99 22:59 ? 00:00:01 postgres: postgres postgres 127.0.0.1(41236) VACUUM
postgres 6443 86102 37 22:59 ? 00:00:00 postgres: postgres postgres 127.0.0.1(41238) VACUUM
postgres 6444 86102 39 22:59 ? 00:00:00 postgres: postgres postgres 127.0.0.1(41240) VACUUM
postgres=# create table test3(id int);
CREATE TABLE
insert into test4 select id from generate_series(1,1250) t(id);
INSERT 0 1250
postgres=# select pg_relation_filepath('test4');
pg_relation_filepath
----------------------
base/13580/17284
(1 row)
postgres=# show autovacuum_vacuum_insert_threshold;
autovacuum_vacuum_insert_threshold
------------------------------------
1000
(1 row)
postgres=# show autovacuum_vacuum_insert_scale_factor;
autovacuum_vacuum_insert_scale_factor
---------------------------------------
0.2
(1 row)
postgres@bogon-> ll 17284*
-rw------- 1 postgres postgres 48K Jul 7 20:41 17284
-rw------- 1 postgres postgres 24K Jul 7 20:41 17284_fsm
-rw------- 1 postgres postgres 8.0K Jul 7 20:41 17284_vm
postgres=# CREATE TABLE test
postgres-# (
postgres(# id SERIAL
postgres(# ,tdate TIMESTAMPTZ
postgres(# ,name varchar(50)
postgres(# );
CREATE TABLE
INSERT INTO test
(tdate, name)
SELECT x, 'cuipeng'
FROM generate_series('2021-01-01 00:00:00'::timestamptz, '2021-09-16 00:00:00'::timestamptz,'5 seconds'::interval) a(x);
INSERT 0 4457521
postgres=# SELECT pg_size_pretty(pg_total_relation_size('test'));
pg_size_pretty
----------------
222 MB
(1 row)
postgres=# VACUUM VERBOSE test;
INFO: vacuuming "public.test"
INFO: "test": found 0 removable, 134 nonremovable row versions in 1 out of 28392 pages
DETAIL: 0 dead row versions cannot be removed yet, oldest xmin: 528
There were 0 unused item identifiers.
Skipped 0 pages due to buffer pins, 0 frozen pages.
0 pages are entirely empty.
CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.
VACUUM
postgres=# DELETE FROM test WHERE tdate BETWEEN '2021-01-01' AND '2021-02-01';
DELETE 535681
postgres=# VACUUM VERBOSE ANALYZE test;
INFO: vacuuming "public.test"
INFO: "test": removed 535681 row versions in 3412 pages
INFO: "test": found 535681 removable, 137 nonremovable row versions in 3413 out of 28392 pages
DETAIL: 0 dead row versions cannot be removed yet, oldest xmin: 530
There were 0 unused item identifiers.
Skipped 0 pages due to buffer pins, 0 frozen pages.
0 pages are entirely empty.
CPU: user: 0.02 s, system: 0.01 s, elapsed: 0.63 s.
INFO: analyzing "public.test"
INFO: "test": scanned 28392 of 28392 pages, containing 3921840 live rows and 0 dead rows; 30000 rows in sample, 3921840 estimated total rows
VACUUM
INFO: "test": removed 535681 row versions in 3412 pages
found 535681 removable 535681可移动行
versions in 3412 pages 总3412页面
postgres=# VACUUM VERBOSE ANALYZE test;
INFO: vacuuming "public.test"
INFO: "test": found 0 removable, 134 nonremovable row versions in 1 out of 28392 pages
DETAIL: 0 dead row versions cannot be removed yet, oldest xmin: 532
There were 0 unused item identifiers.
Skipped 0 pages due to buffer pins, 3411 frozen pages.
0 pages are entirely empty.
CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.
INFO: analyzing "public.test"
INFO: "test": scanned 28392 of 28392 pages, containing 3921840 live rows and 0 dead rows; 30000 rows in sample, 3921840 estimated total rows
VACUUM







