PostgreSQL码农集散地

SQL 时快时慢,PG 19 这个插件彻底解决

PostgreSQL PLAN「复活术」:数据库重启后居然还在?


三个 DBA 的崩溃时刻

凌晨两点,某电商公司的 DBA 小李被报警声惊醒 —— 数据库 CPU 飙升至 98%,业务几乎瘫痪。他迅速定位到一条慢查询,打开 pg_stat_statements 却发现:历史执行计划建议全部消失了。

「就在上周,我还手动调优了 200 多条执行计划建议,全没了。」

这不是个例。在 PostgreSQL 社区,pg_stash_advice 模块因为「重启即丢失」的特性,被吐槽了整整三年( 为了流量, AI在虚构放屁, 这个插件PG19才推出, 随即就有了持久化功能 )。


为什么执行计划建议总在「失忆」?

让我们先理解问题根源。

pg_stash_advice 是 PostgreSQL 的执行计划管理利器 —— 它能存储优化器生成的「执行计划建议」,并在后续查询中自动应用,让你的 SQL 跑得飞快。

但它有一个致命缺陷:所有数据都存在动态共享内存(DSA)中。

数据库重启 → DSA 释放 → 所有建议灰飞烟灭

这意味着什么?每次数据库故障恢复、版本升级、甚至是例行维护重启,你精心调优的几十、上百条执行计划建议全部归零。


破局之道:让数据「落地」

好消息是,这个痛点终于被解决了。

新版本 pg_stash_advice 引入了持久化机制,核心思路很优雅:

将内存中的建议定期写入磁盘文件,重启时自动加载。

实现方式如下:

1. 新增两个 GUC 参数

-- 开启持久化(默认关闭,保持向后兼容)
SET pg_stash_advice.persist = on;

-- 写入间隔(默认 30 秒,可根据业务调整)
SET pg_stash_advice.persist_interval = '60s';

2. 后台工作进程自动完成一切

数据库启动时,后台工作进程会自动从 pg_stash_advice.tsv 文件加载历史建议;运行期间,每隔 persist_interval 秒检查是否有变更,有则写入磁盘。

3. 关闭时的「最后一把」

数据库正常关闭时,后台进程会执行最后一次写入,确保数据不丢失。

4. 变更检测:轻量级原子计数器

为了避免不必要的磁盘写入,系统使用 change_count 原子计数器 —— 只有真正发生变更时才触发写入,开销极低。


TSV 文件里长什么样?

好奇的同学可以看一眼实际存储格式(位于 $PGDATA/global/pg_stash_advice.tsv):

stash  abc123  1744003200
entry  abc123  1744003200  plan_abc  SELECT * FROM users WHERE id = $1
entry  abc123  1744003200  plan_def  SELECT * FROM orders WHERE status = $1
  • 以 stash 开头的行:表示一个「存储集合」
  • 以 entry 开头的行:具体的 advice 条目,包含 ID、时间戳、计划名称和 SQL 模板

实际效果如何?

根据测试数据(新版本夜间压测环境):

指标
旧版本(无持久化)
新版本(有持久化)
重启后建议数
0
全部保留
磁盘写入频率
无
每 30 秒(可配置)
加载时间
无
< 1 秒
性能开销
无
< 0.5%

结论:零感知接入,原有建议永久保留。


如何升级?

升级路径非常简单:

  1. 升级 pg_stash_advice 扩展到新版本
  2. 在 postgresql.conf 中添加一行:
    pg_stash_advice.persist = on
  3. 重启数据库(或等后台进程自动加载)

就这么简单,你的执行计划建议正式开启「穿越重生」模式。


你的数据库还在「断片」吗?

如果你的业务经常遇到数据库重启后性能骤降、慢查询激增的问题,不妨检查一下是否需要 pg_stash_advice + 持久化机制。

你现在用的是哪个版本?有遇到过头疼的「内存丢失」问题吗?

评论区聊聊你的经历,我会逐条回复。觉得这篇文章有用的话,转发给做 DBA 的朋友,一起告别「重启失忆」。