Autovacuum 从 PostgreSQL 8.1 起就承担着回收死元组、刷新统计信息和防止事务 ID 回卷的工作。PostgreSQL 19 的关键变化,不是增加另一条触发规则,而是让维护任务有了明确的优先级:数据库和表都会先接受风险评估,autovacuum worker 再处理最紧迫的对象。
这改变了一个长期存在的问题。过去,接近事务 ID 回卷的表与刚刚越过统计信息更新阈值的表,可能只是按系统目录中的顺序等待。现在,调度器终于能够区分“该更新统计信息了”和“再不冻结就可能阻塞写入”这两种完全不同的紧迫程度。
从目录顺序变成五维评分
新的调度过程分为两层。Launcher 先选择数据库:接近事务 ID 或 multixact ID 回卷风险的数据库优先,否则倾向于选择最久没有得到维护的数据库。进入数据库后,worker 为候选表计算分数,并按分数排序。
每张表有五个组成分数:
- 事务 ID 年龄,反映普通事务 ID 的冻结压力。
- Multixact ID 年龄,反映共享行锁等场景积累的 multixact 冻结压力。
- 死元组数量,代表 VACUUM 回收空间的需求。
- 新插入元组数量,代表插入型表的维护压力。
- 自上次 ANALYZE 以来的数据变化量,代表统计信息过期程度。
这些分数本质上都在描述“当前状态超过触发阈值多少”。表的总优先级不是五项之和,而是取加权后最高的一项。这样设计有一个重要结果:只要某一种风险足够突出,其他维度较低也不会掩盖它。
例如,一张追加写日志表可能没有死元组,因此 VACUUM 回收分数为零;但大量 INSERT 会同时推高插入分数和 ANALYZE 分数。另一张任务队列表频繁 UPDATE、DELETE,死元组回收压力更大。最终谁先处理,取决于两张表各自最高的组成分数,以及管理员给各维度设置的权重。
用系统视图看见调度器的判断
PostgreSQL 19 新增了 pg_stat_autovacuum_scores,用于展示当前数据库中各表的总体分数与组成分数。这让 autovacuum 的决策从“根据日志猜原因”变成了可以查询、排序和监控的数据。
在 PostgreSQL 19 环境中,可以先执行下面的只读检查。这里使用 SELECT *,是为了兼容开发版本可能发生的列名调整;正式接入监控时,应根据实际安装版本显式选择列名。
psql -X -v ON_ERROR_STOP=1 <<'SQL'
SELECT version();
SELECT *
FROM pg_stat_autovacuum_scores
LIMIT 5;
SELECT *
FROM pg_stat_autovacuum_scores
ORDER BY score DESC
LIMIT 20;
SQL
如果当前构建中的总体分数列不叫 score,可以先查询视图结构:
psql -X -v ON_ERROR_STOP=1 <<'SQL'
SELECT
ordinal_position,
column_name,
data_type
FROM information_schema.columns
WHERE table_schema = 'pg_catalog'
AND table_name = 'pg_stat_autovacuum_scores'
ORDER BY ordinal_position;
SQL
生产监控不应只截取一次快照。更实用的做法是定时采集最高分表,同时关联 pg_stat_all_tables 中的死元组、最近一次 autovacuum 和 analyze 时间。可以这样实践:先确认视图列名,再将下面的 score 和关联键改成当前 PostgreSQL 19 构建实际提供的名称。
SELECT
s.*,
st.n_live_tup,
st.n_dead_tup,
st.last_autovacuum,
st.last_autoanalyze
FROM pg_stat_autovacuum_scores AS s
JOIN pg_stat_all_tables AS st
ON st.relid = s.relid
ORDER BY s.score DESC
LIMIT 25;
分数高并不自动等于故障。更值得告警的是“某张表长期保持高分但一直没有被处理”,这可能说明 worker 数量、I/O 预算、锁竞争或单表维护耗时已经成为瓶颈。
权重把业务偏好写进维护队列
PostgreSQL 19 为五个组成分数提供了对应的缩放权重。默认权重为 1,即五类维护需求被平等对待。提高某项权重会放大对应分数,降低权重则会让该项在排序中退后。将五项全部设为 0,可以恢复接近旧版本的目录顺序策略。
这使管理员能够表达具体政策。例如,频繁更新的业务库可能更重视死元组回收,而分析型系统可能更关注追加写事实表的插入与统计信息压力。假设日志表的 ANALYZE 原始分数为 10000,任务队列的 VACUUM 原始分数为 2800、ANALYZE 原始分数为 6800:
- 默认权重下,日志表以
10000排在队列的6800前面。 - 将 VACUUM 权重调到
2、ANALYZE 权重调到0.5后,日志表降为5000。 - 队列的 VACUUM 分数变成
5600,ANALYZE 分数变成3400,因此队列反超日志表。
由于 PostgreSQL 19 仍处于面向未来版本的阶段,具体 GUC 名称应以安装版本为准,不要把预览构建中的参数名直接写入生产配置。可以用下面的命令发现当前实例实际支持的权重和并行参数:
psql -X -v ON_ERROR_STOP=1 <<'SQL'
SELECT name, setting, unit, context, short_desc
FROM pg_settings
WHERE name LIKE 'autovacuum%weight%'
OR name = 'autovacuum_max_parallel_workers'
ORDER BY name;
SQL
确认名称后,可以通过 ALTER SYSTEM SET 参数名 = '值' 修改,并执行 SELECT pg_reload_conf(); 重新加载。权重参数支持 reload,无须重启。实际变更应一次只调整一两个维度,记录调整前后的高分表、autovacuum 时长、死元组增长和查询计划变化,避免同时改变过多变量而失去判断依据。
INSERT、VACUUM 与冻结不能混为一谈
INSERT 不会像 UPDATE 或 DELETE 那样直接制造死元组,所以追加写表的死元组回收分数可能一直是零。但这不代表它不需要 autovacuum:大量新行会让行数和数据分布统计失真,而且每一行携带的事务 ID 最终都必须冻结。PostgreSQL 从 13 开始就能根据插入活动触发 vacuum,PostgreSQL 19 的评分机制进一步让这种压力可以独立参与排序。
冻结权重尤其需要谨慎。事务 ID 和 multixact ID 的权重不只是简单放大显示出来的分数;将冻结权重提高到 2.0,还会让相关压力在大约一半的通常年龄阈值处变得紧迫。最大冻结年龄仍然有效,但表可能明显更早进入冻结处理。
PostgreSQL 18 引入的 failsafe 年龄仍是硬保护线。表跨过相应年龄后,autovacuum 会取消基于成本的延迟,跳过部分非必要工作,并集中完成冻结。评分系统改善的是正常调度,failsafe 处理的是调度已经来不及的紧急状态。权重不能替代对事务 ID 年龄的监控,也不能成为长期压低冻结优先级的理由。
并行 worker 解决单表吞吐问题
排序正确只解决“先做谁”。如果一张高优先级表带有十几个索引,单个 autovacuum worker 仍可能被它占用很久。PostgreSQL 19 新增 autovacuum_max_parallel_workers,允许一个 autovacuum worker 在索引 vacuum 和 cleanup 阶段招募并行 worker。
该参数默认需要显式启用。下面是一个可改造的配置流程,运行前应根据 CPU、I/O 能力以及实例允许的并行 worker 总量决定数值:
psql -X -v ON_ERROR_STOP=1 <<'SQL'
ALTER SYSTEM SET autovacuum_max_parallel_workers = '4';
SELECT pg_reload_conf();
SHOW autovacuum_max_parallel_workers;
SQL
并行化主要加速索引阶段,并不意味着堆表扫描的所有工作都会线性加速。它还会与查询、手工 VACUUM 和其他并行任务争夺 CPU 与 I/O。对索引少的小表,提高该参数可能几乎没有收益;对宽表和多索引表,收益才更可能明显。
升级时的落地顺序
PostgreSQL 19 的保守采用方式,是先使用默认权重收集数据,再决定是否干预:
- 验证
pg_stat_autovacuum_scores的实际列结构,将最高分和各组成分数接入时序监控。 - 观察高分表是否能及时下降,并关联死元组、冻结年龄、锁等待和 autovacuum 持续时间。
- 保持五项权重为默认值,至少覆盖一个有代表性的业务周期。
- 只有出现稳定、可解释的维护错序时,才小幅调整对应权重。
- 在多索引大表确实拖慢 worker 时,再启用并逐步提高
autovacuum_max_parallel_workers。 - 为事务 ID 与 multixact ID 年龄保留独立告警,不把评分视图当作唯一的防回卷保护。
这次变化的真正价值,不是要求每个集群立即调六个参数,而是让 autovacuum 第一次具备了可观察、可表达的优先级模型。默认配置提供稳妥起点;当工作队列、追加写仓库或超高事务量系统出现维护争用时,管理员也终于有工具说明集群究竟应该先救哪张表。