Autovacuum 是 PostgreSQL 的"自动保洁阿姨",负责清理死元组、防止表膨胀。
但长期以来有个致命问题:它只能用单线程。
想象一下:
PostgreSQL 最新版本支持 autovacuum 并行 vacuum:
之前:只有 1 个 worker,顺序处理所有索引
现在:1 个 leader + 多个 worker,同时处理多个索引(最多 5 个)
注:leader 本身也处理 1 个索引,所以如果有 4 个 worker,最多同时处理 5 个索引。每个 worker 处理 1 个或多个索引(不同 worker 处理不同索引)。
数据来源参考:12 索引的表,启用 4 个并行 worker
场景 | 优化前 | 优化后 |
|---|---|---|
索引清理时间(12 索引) | ~45 分钟 | ~12 分钟 |
总体 vacuum 时间 | 60+ 分钟 | ~30 分钟 |
死元组清理延迟 | 3-4 天 | 1 天内 |
表膨胀程度 | 2x 正常大小 | 1.2x 以内 |
注:具体效果取决于索引数量、大小及
maintenance_work_mem配置。
-- postgresql.conf
autovacuum_max_parallel_workers = 4
max_parallel_workers = 8
-- 为单个表设置(以分区表为例)
ALTER TABLE orders_history_2025_01 SET (
autovacuum_parallel_workers = 4
);
ALTER TABLE orders_history_2025_02 SET (
autovacuum_parallel_workers = 4
);
语义说明:
-1(默认):让系统自动决定0:禁用该表的并行 vacuum正整数:使用指定数量(同时受 GUC 上限约束)Leader Worker
├── 负责协调和总体进度
│
└── Worker 1 ──► 处理索引 1, 2
└── Worker 2 ──► 处理索引 3, 4
└── Worker 3 ──► 处理索引 5, 6
└── Worker 4 ──► 处理索引 7, 8
所有 worker 共享 cost balance 调度
关键点:cost balance(vacuum 的 I/O 节流)是共享的,不是每个 worker 独立叠加。所以不会因为开并行 worker 就突然疯狂消耗 I/O。
Autovacuum 的 cost 参数可以在运行时修改:
ALTER SYSTEM SET autovacuum_vacuum_cost_delay = 10;
SELECT pg_reload_conf();
修改后,leader 会自动把新参数同步给所有 worker,不需要重启 vacuum。
并行有前提条件:
min_parallel_index_scan_size 控制)amparallelvacuumoptions 支持并行小表不要开并行: 对于小于 100MB 的表,并行的进程启动开销可能反而更大。
-- 小表显式禁用
ALTER TABLE small_config SET (
autovacuum_parallel_workers = 0
);
以前:autovacuum 单线程,大表 vacuum 要等几小时。
现在:autovacuum 并行化,同样的活几十分钟搞定。
最佳实践:
autovacuum_vacuum_cost_delay 使用,减少对业务的影响