PostgreSQL码农集散地

PG 19 垃圾回收变聪明了,不信看这个视图

痛点回顾:数据库越来越慢,autovacuum 到底在忙什么?哪些表该先清理?XID 年龄有没有风险?以前只能靠猜。

现在,一个新视图让这一切都透明了。

01 这个视图能干啥?

pg_stat_autovacuum_scores,名字很长,但功能很直接—— 它给每个表打了一个"紧急程度分" 。

分数越高,说明这个表越急需 autovacuum 处理。

SELECT relname, score, vacuum_score, xid_score
FROM pg_stat_autovacuum_scores
ORDERBY score DESC
LIMIT10;

结果大概长这样:

   relname    | score | vacuum_score | xid_score
--------------+-------+--------------+------------
 orders       |  1.85 |      1.85    |     0.00
 users        |  0.95 |      0.95    |     0.00
 user_sessions|  0.85 |      0.00    |     0.85

orders 表分数 1.85,说明死元组堆积严重;user_sessions 虽然死元组不多,但 XID 年龄偏高,可能有 wraparound 风险。

02 分数是怎么算出来的?

不是简单看死元组数量,而是一个多维度评分机制:

组件
含义
vacuum_score
死元组清理的紧迫程度
xid_score
事务ID年龄的紧迫程度
mxid_score
多事务ID年龄的紧迫程度
analyze_score
统计信息过期的紧迫程度

总分取各组件的最大值——哪个最严重,就按哪个处理。

这解释了为什么有时候死元组不多的表,反而分数很高:因为它的 XID/MXID 年龄可能已经接近警戒线了。

03 实战场景

场景一:揪出 XID wraparound 高风险表

SELECT * FROM pg_stat_autovacuum_scores
WHERE xid_score > 0.8OR for_wraparound = true
ORDERBY xid_score DESC;

如果 XID 耗尽,数据库将无法写入新数据——这是 PostgreSQL 最严重的事故之一。现在能精确定位到具体是哪张表。

场景二:理解多表竞争时的处理顺序

当 autovacuum worker 只有 1 个槽位,但 10 张表都需要清理时,它会按分数从高到低处理。

想知道你的表为什么迟迟没被 vacuum?查一下分数就知道了。

场景三:调优 autovacuum 参数

如果想让 autovacuum 优先处理表膨胀(而非 freeze 年龄):

ALTERSYSTEMSET autovacuum_vacuum_score_weight = 2.0;
ALTERSYSTEMSET autovacuum_freeze_score_weight = 0.5;
SELECT pg_reload_conf();

调优前后的分数变化,可以量化验证效果。

04 告警这样配

-- 高风险:XID 分数 > 0.8 或 for_wraparound = true
CREATEORREPLACEFUNCTION check_autovacuum_risk()
RETURNSvoidAS $$
DECLARE
    risk_count INTEGER;
BEGIN
SELECTCOUNT(*) INTO risk_count
FROM pg_stat_autovacuum_scores
WHERE xid_score > 0.8OR for_wraparound = true;

    IF risk_count > 0 THEN
        RAISE WARNING '⚠️ % 张表需要立即关注 autovacuum', risk_count;
ENDIF;
END;
$$ LANGUAGE plpgsql;

配合 pg_cron 或外部监控工具,实现自动告警。

05 一句话总结

以前:autovacuum 是黑箱,DBA 只能被动等事故。

现在:有了 pg_stat_autovacuum_scores,谁该先清理、为什么、有多紧急,一目了然。


推荐配置:将高分数表的查询纳入日常巡检,特别是 xid_score 持续走高的表,提前处理远比事后补救划算得多。