PostgreSQL vacuum
vacuum 是PG数据库垃圾回收,PG官方关于vacuum的介绍参考:https://www.postgresql.org/docs/12/routine-vacuuming.html
vacuum的主要动作:磁盘清理、更新统计信息、重组数据、解决事务ID回滚问题:
1)清除 update、delete 操作后留下的死元组;
2)跟踪表块中可用空间,更新 free space map;
3)更新 VM 即 visibility map(可见性映射文件map,vacuum 会根据该文件来选择是否扫描某个 page。select * from pg_visibility('test01');)、index only scan,后续 vacuum 会用到,更新以后,提高后续 vacuum 的效率;
4)冻结表中的行,防止事务ID回滚;
5)配合 analyze、定期更新统计信息(pg_stat_all_tables);
vacuum SQL 语法:
VACUUM [ ( { FULL | FREEZE | VERBOSE | ANALYZE | DISABLE_PAGE_SKIPPING } [, ...] ) ] [ table_name [ (column_name [, ...] ) ] ]
VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] [ table_name ]
VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] ANALYZE [ table_name [ (column_name [, ...] ) ] ]
vacuum 可以有效解决表膨胀的问题。
表膨胀是指有效数据量不变,但表越来越大,扫描的效率变低,因为:PG的MVCC写数据时,旧数据不删除,把新数据插入,将旧数据标记为无效,在数据库系统 auto vacuum 清理死元组之前一直占用空间,执行 update 就是 insert + delete 的原理,依然会导致表膨胀,而执行 vacuum 可以有效解决表膨胀的问题。
vacuum有两种:标准vacuum 和 vacuum full。
标准vacuum: 基本可以 online 操作(DML 运行正常,但不能执行 ALTER TABLE),执行速度快,但能回收的磁盘空间很少。
vacuum full: 能回收更多的磁盘空间,但运行速度要慢很多,它需要对表加独占锁(阻塞一切读写操作),因此不能与该表的其他操作并发进行;此外还需要额外空间存储表副本。
vacuum full 会对表进行一个重组,执行后表的 OID 会变,定位表的 OID 的时候,不能通过 pg_class 的 oid 来找,要通过 pg_class 的 relfilenode 来找。
vacuum full 一般日常操作中不推荐使用。
insert into test01(id, info) values(5, 'sss');
update test01 set info='sss_xxxx' where id=5;
vacuum test01;
select pg_relation_filepath('test01');
testdb01=> select pg_relation_filepath('test01');
pg_relation_filepath
----------------------
base/16385/18906
(1 row)
vacuum full test01;
select pg_relation_filepath('test01');
testdb01=> select pg_relation_filepath('test01');
pg_relation_filepath
----------------------
base/16385/27204
(1 row)
testdb01=> select oid,relname,relfilenode from pg_class where relname='test01';
oid | relname | relfilenode
-------+---------+-------------
18906 | test01 | 27204
(1 row)
可见 vacuum full 执行以后,relfilenode 发生了变化。