由 John Doe 四月 14, 2026
PostgreSQL 新增了 pg_stash_advice 扩展模块,实现了基于查询 ID 的执行计划建议自动应用能力。无需修改应用代码、无需重启服务,即可为任意查询永久绑定最优执行计划,彻底解决了统计信息波动、规划器误判导致的慢查询回退难题。

特性提交日志
新增 pg_stash_advice 扩展模块。
该模块支持从内存中的建议缓存(advice stash) 中自动提供执行计划建议字符串。
建议缓存存储在动态共享内存中,服务器重启后必须重新创建并重新填充内容。
如果将 pg_stash_advice.stash_name 设置为某个建议缓存的名称,并且已启用查询标识符(queryID),则在每次对查询进行执行计划规划时,都会根据该查询的查询标识符在建议缓存中进行查找,并使用与之关联的计划建议字符串(如果存在)。
讨论:http://postgr.es/m/CA+TgmoaeNuHXQ60P3ZZqJLrSjP3L1KYokW9kPfGbWDyt+1t=Ng@mail.gmail.com
特性示例
pg_stash_advice 扩展允许您将执行计划建议字符串存放在动态共享内存中,并实现自动应用。
建议缓存(advice stash)是一种查询标识符到执行计划建议字符串的映射关系。
每当会话需要为某个查询生成执行计划时,如果该查询的 ID 存在于对应的建议缓存中,计划建议字符串会被自动应用,以指导查询规划。
需要注意的是,建议缓存存储在动态分配的共享内存中。这意味着在决定缓存多少计划建议时,需要格外关注内存占用情况。
此外,建议缓存及其内容可以选择性地自动持久化到磁盘并从磁盘重新加载,该行为由 pg_stash_advice.persist 参数控制。
基础操作
创建一个名为prod_advice的建议缓存:
SELECT pg_create_advice_stash('prod_advice');
查看所有已创建的缓存:
SELECT * FROM pg_get_advice_stashes();
查看指定缓存的内容:
SELECT query_id, advice_string FROM pg_get_advice_stash_contents('prod_advice');
设置当前会话使用prod_advice缓存:
SET pg_stash_advice.stash_name = 'prod_advice';
删除指定查询的建议:
SELECT pg_set_stashed_advice('prod_advice', 628498234759226701, NULL);
删除整个缓存:
SELECT pg_drop_advice_stash('prod_advice');
获取查询 ID 与计划建议
方法1:通过EXPLAIN VERBOSE获取单个查询的ID
EXPLAIN (VERBOSE, COSTS OFF)
SELECT * FROM orders WHERE customer_id = 1001 AND order_date > '2026-01-01';
-- 输出中会包含:Query Identifier: 476204883729405722
方法2:从pg_stat_statements批量获取慢查询ID
SELECT queryid, query FROM pg_stat_statements WHERE total_time > 1000 ORDER BY total_time DESC;
方法3:获取最优计划的建议字符串
EXPLAIN (PLAN_ADVICE, COSTS OFF)
SELECT * FROM orders
WHERE customer_id = 1001 AND order_date > '2026-01-01';
-- 输出中会包含:Plan Advice: INDEX_SCAN(orders orders_customer_id_idx)
绑定并验证建议
将查询ID与建议绑定:
SELECT pg_set_stashed_advice(
'prod_advice',
476204883729405722,
'INDEX_SCAN(orders orders_customer_id_idx)'
);
验证:再次执行EXPLAIN,会看到建议已自动应用
EXPLAIN (COSTS OFF)
SELECT * FROM orders WHERE customer_id = 1001 AND order_date > '2026-01-01';
-- 输出末尾会显示:
-- Supplied Plan Advice:
-- INDEX_SCAN(orders orders_customer_id_idx) /* matched */
非常不错的体验,感谢所有参与的社区人员,PostgreSQL 19 值得期待。
参考
提交日志:https://git.postgresql.org/pg/commitdiff/e8ec19aa321abc89fb4fd277c994f14680ba17db