PostgreSQL autovacuum 与表膨胀
监控 dead tuples、冻结风险和 vacuum 进度并安全调整高写入表
标准 VACUUM 的目标不只是“释放空间”:它让 dead row versions 可复用、维护 planner statistics 和 visibility map,并防止 transaction ID/multixact wraparound。多数系统应保持 autovacuum 开启。
日常观测
SELECT
schemaname, relname,
n_live_tup, n_dead_tup,
last_vacuum, last_autovacuum,
vacuum_count, autovacuum_count,
last_analyze, last_autoanalyze
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC
LIMIT 30;统计是估算且会重置,不能仅凭一个 n_dead_tup 阈值判断膨胀。结合表大小、更新速率、查询延迟、autovacuum 日志和趋势。
查看正在运行的 vacuum:
SELECT
pid, datname, relid::regclass AS relation,
phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed,
index_vacuum_count, dead_tuple_bytes, num_dead_item_ids,
indexes_total, indexes_processed
FROM pg_stat_progress_vacuum;这些字段名对应 PostgreSQL 18;较早 major 的 progress view 列可能不同,跨版本监控应先核对目标版本目录。
为什么没有触发或跟不上
- 表很大,默认 scale factor 对应的变更行数过高;
- worker、I/O 或维护内存不足;
- 长事务、prepared transaction、复制槽或 standby snapshot 阻止回收;
- vacuum 经常被冲突锁取消;
- 写入峰值持续高于清理能力。
针对已验证的热点表覆盖参数,而不是先全局激进调整:
ALTER TABLE app.events SET (
autovacuum_vacuum_scale_factor = 0.02,
autovacuum_vacuum_threshold = 1000,
autovacuum_analyze_scale_factor = 0.01
);参数只是示例。根据表大小和每天变更量计算触发频率,并观察 I/O、WAL、延迟与实际完成时间。
手工维护边界
VACUUM (ANALYZE, VERBOSE) app.events;普通 VACUUM 主要让空间在关系内部复用,通常不会把文件缩回操作系统。VACUUM FULL 会重写整张表、需要额外磁盘并获取 ACCESS EXCLUSIVE 锁,不是日常清理命令。
不要关闭 autovacuum 解决性能问题
先找出具体表、阶段、等待事件和资源瓶颈。关闭 autovacuum 会积累 dead tuples、陈旧统计和冻结风险;反 wraparound vacuum 即使表级设置关闭也可能运行。
Last updated on