一、VACUUM概念
VACUUM 是 PostgreSQL 中的一种维护命令,用于清理和优化数据库中的表。其主要功能包括:
回收空间:删除标记为删除的行,释放磁盘空间。
防止表膨胀:通过回收无效行来防止表变得过大,提高查询效率。
更新统计信息:帮助查询优化器生成更高效的执行计划。
二、vacuum和vacuum full的区别
VACUUM 主要用于清理和回收数据库中标记为删除的行,释放空间并防止表膨胀,而不锁定表,可以在表仍然可读写的情况下运行。
VACUUM FULL:重写整个表,完全释放空间并压缩表,在操作期间会锁定表,因此表不可访问。也会创建表的副本,磁盘空间加倍,所以空间不足的情况下不要运行。
三、vacuum监控和调优
(一)监控
1、dead tuple
死行会导致表膨胀并且查询变慢,因此需要持续关注表中的 dead tuple 和 live tuple 比率,并进行优化
select relname,n_dead_tup,n_live_tup from pg_stat_user_tables;
select relname,coalesce(round(n_dead_tup * 100 / (case when n_live_tup + n_dead_tup = 0 then null else n_live_tup + n_dead_tup end ),2),0.00) as dead_tup_ratio from pg_stat_user_tables order by dead_tup_ratio desc limit 5;
2、tuple空间
select relname,relpages / reltuples as per_tuple_page from pg_class where reltuples!=0;
select relname,reltuples / relpages as per_page_tuple from pg_class where reltuples!=0;
3、 pgstattuple
pgstattuple模块提供了各种功能来获取元组级别的统计信息,具体信息大家可以参考https://www.PostgreSQL.org/docs/current/pgstattuple.html
(二)调优
1、表参数
控制autovacuum执行频率的参数有
autovacuum_analyze_scale_factor
autovacuum_analyze_threshold
autovacuum_vacuum_scale_factor
autovacuum_vacuum_threshold
当表上变化的行数达到条件时,autovacuum 进程会对其进行 vacuum。主要条件是:
autovacuum_vacuum_scale_factor 和 autovacuum_vacuum_threshold 控制执行条件。
默认 autovacuum_vacuum_scale_factor 为 0.2(表膨胀超过 20% 即触发),threshold 为 50 以防止小表频繁触发。
可以单独设置频繁更新或删除的表,示例如下:
ALTER TABLE t SET (autovacuum_vacuum_scale_factor = 0.1);
ALTER TABLE t SET (autovacuum_vacuum_threshold = 10000);
analyze 也通过类似机制控制,由 autovacuum_analyze_scale_factor 和 autovacuum_analyze_threshold 参数决定。
2、清理
为了不影响用户使用,PostgreSQL引入了基于代价的清理机制,以减少CPU和IO占用:
- 清理过程:从磁盘逐个读取页面(8K),使用VM文件判断是否有dead tuple,有则清理并标记为dirty再写出。
- 代价参数:
vacuum_cost_page_hit = 1
:从共享缓存中找到的缓冲区清理代价,默认值1。
vacuum_cost_page_miss = 10
:必须从磁盘读取的缓冲区清理代价,默认值10。
vacuum_cost_page_dirty = 20
:修改干净块后清理代价,默认值20。
- 成本限制:
- 从共享缓存读页面:80MB/s
- 从磁盘读页面:8MB/s
- 写出脏页:4MB/s
- 假设
autovacuum_vacuum_cost_delay = 20ms
,autovacuum_vacuum_cost_limit = 200
,每秒能做50轮,每轮200代价,实际工作量:
- 优化建议:
- 对于有缓存的RAID卡,
autovacuum_vacuum_cost_limit
设置为1000。 - 对于SSD,设置为10000。
过小的 autovacuum_vacuum_cost_limit
会导致频繁休眠,旧数据无法及时清理,建议适当增加该参数值。
3、工作进程数
PostgreSQL启动 autovacuum_max_workers
来清理不同的数据库/表,大表和小表的代价不同,防止大表阻塞小表:
- 全局成本限制:
cost_limit
被所有 worker 共享,多个 worker 并不一定能提高速度。 - 当清理跟不上时:提高 worker 数无效,应提高
cost
参数,可以在单独的表上设置:
ALTER TABLE t SET (autovacuum_vacuum_cost_limit = 1000);
ALTER TABLE t SET (autovacuum_vacuum_cost_delay = 10);
这些表的清理工作成本独立于全局计算,提高灵活性,但实际生产中很少使用此特性:
- 通常需要唯一的全局后台清理成本限制。
- 多个 worker 有时一起限制,有时独立,难以监控和分析。
4、表分区
由于VACUUM
不能在同一张表上并发进行,因此表不能太大。如果表超过 3000 万记录或 32GB,应使用分区表。对于旧版本 PostgreSQL,通过表继承实现分区,在 10.x 版本之前语法不方便,导致一些用户未使用分区表。即使在 10.x 之后,性能仍略差。最佳实践是使用pg_pathman
插件来实现分区表,避免分区带来的性能问题。
四、vacuum总结
不要禁用autovacuum;
在update delete频繁的表上单独设置fillfactor参数,比如80%;
在update delete频繁的业务中,减低scale factor,这样清理进程可以及时的进行;
在好的硬件下,提高限流阀,这样清理进程不会被中断;
单独提高autovacuum_max_worker不行,需要和参数一起调整;
使用alter table设置参数要慎重,这会让系统变得复杂。