pg_plan_advice:PostgreSQL 查询计划稳定性的新利器

John Doe 八月 11, 2026

PostgreSQL 作为全球知名的开源数据库,一直在优化查询性能和计划的可控性上持续发力。

目录

image

今天我们聚焦一个即将于 PostgreSQL 19 中发布的贡献模块:pg_plan_advice。它不仅提供了类似“查询提示”的功能,更致力于解决查询计划的稳定性问题,帮助数据库管理员和开发者更灵活、精确地控制查询执行。

什么是 pg_plan_advice?

pg_plan_advice 是 PostgreSQL 的一个贡献模块,其核心功能是:

  • 生成和接受一个迷你“计划建议”语言(mini-language),描述查询优化器的关键决策。
  • 允许用户查看当前查询计划做出了哪些决策(以字符串形式展示)。
  • 支持将这个建议字符串重新传给优化器,强制复用之前的计划决策,或者通过修改建议字符串,尝试引导优化器做出不同的决策。

简而言之,pg_plan_advice 既能用作查询提示(Hint),也能实现查询计划的稳定性保障

pg_plan_advice 有何不同?

许多人会将它等同于传统的“查询提示”,但 pg_plan_advice 更强调的是:

  • 计划稳定性:保证生产环境中关键查询的计划不会因统计信息的变化或优化器升级而突然改变。
  • 灵活性:可用此系统强制执行稳定计划,也可主动调整计划。
  • 风险与实验价值:坏的建议可能导致糟糕计划和性能问题,但它为数据库调试、测试和研究优化器行为提供了极大便利。

相比已有的纯提示系统或保存完整计划再恢复的方案,pg_plan_advice 提供的是一种“语义级”的控制,既避免了旧计划格式的失效问题,也兼顾了灵活的调整空间。

pg_plan_advice 的核心设计挑战

1. 设计一个表达计划决策的“建议语言”

  • 表达计划决策的关键要素:如表的别名、连接顺序、连接方法、扫描方式等。
  • 消除歧义:在复杂查询(嵌套子查询、表别名重复、分区表)中,如何唯一且无歧义地标识各个关系。
  • 语法设计:采用类似其它hint系统的“操作符+目标列表”方式,同时针对复杂场景扩展为包含别名编号、子查询标识和分区信息的多层结构。
  • 通过括号分层表达连接顺序和对输入关系的精确定位,确保能准确复现或重构计划。

2. 生成计划建议的技术难点

  • 优化器生成的最终计划有时是“简化”的,如对无效左连接(join condition = false)不扫描某些表,导致计划节点被替代或消失,进而造成建议语言无法透彻描述这些情况。
  • 解决方案是在EXPLAIN输出和计划树中加入额外元信息,明确标识每个节点的来源,使建议生成可全面且准确。
  • 处理Subquery ScanAppendMergeAppend等节点的“消失现象”,增加隐式信息保全计划结构。

3. 强制计划建议的执行策略

  • 如何让优化器“乖乖地”按照建议做出决策,而不是绕开或无视?
  • 通过“禁用(Disable)不符合建议的路径”策略,确保只有符合要求的计划路径可以被选中。
  • 引入了创新的位掩码pgs_mask,支持对计划全局、表、连接、连接方法甚至更细粒度的路径禁用。
  • 使用负面限制(禁止某些连接顺序等)间接实现正面目标,解决了复杂的计划生成功能冲突。
  • 注意:若建议字符串不合理,可能禁用所有可选路径,导致计划极差但不会失败;用户需谨慎使用。

如何使用 pg_plan_advice?

两种载入建议字符串的方法

直接通过会话参数

SET pg_plan_advice.advice = '你的建议字符串';
-- 然后执行查询,后续需要清空该参数以避免影响其他查询
RESET pg_plan_advice.advice;

借助 pg_stash_advice 模块,根据查询 ID 自动匹配建议字符串

  1. 创建“建议仓库”(stash),映射查询ID到建议字符串。
  2. 设置会话参数指向该“建议仓库”。
  3. 查询执行时自动匹配计划建议。

该方法操作灵活,且可用 ALTER ROLE 或 ALTER DATABASE 持久化配置,零侵入业务代码,但对查询ID的依赖和单一映射限制了一定场景适用性。

拓展接口

pg_plan_advice 设计了可插拔的 Advisor Hook,允许用自定义代码动态生成和应用建议字符串,实现自动化优化策略或更复杂的实验。

pg_plan_advice 未来展望与开发方向

  • 扩展控制范围:目前对扫描类型、连接顺序和连接方法有较好控制,但对聚合方式、并行度等仍无直接控制,未来可支持更多计划层面。
  • 引入基于估算行数(cardinality)的建议,为优化器提供更准确选择依据。
  • 自动建议生成系统:减少人工干预,智能判断何时启用建议,结合历史执行表现调整计划。
  • 测试和调优工具:利用随机建议计划验证查询正确性,寻找估算偏差,辅助优化算法改进。
  • 应用层注解传递:目前建议字符串通过参数或stash传递,未来或支持在查询注释中直接嵌入,提升易用性。

实用建议与注意事项

  • 风险意识:错误建议不会导致规划失败,但可能产生极差执行计划,所以上线务必测试充分。
  • 配合准备语句使用要当心:计划建议只在规划时生效,准备语句的复用和重新规划需要保证建议字符串一致,否则可能不会生效。
  • 使用反馈机制追踪建议应用情况,通过EXPLAIN输出可了解具体哪些建议被采纳,哪些无效,方便维护调整。
  • 建议结合业务场景推进:计划稳定性多见于复杂且重要的生产查询,避免对简单查询盲目使用。

总结

pg_plan_advice 是 PostgreSQL 在计划稳定性与灵活性控制上一次重要且创新的尝试。它既不是简单的查询提示,也不是死板的计划快照,而是一个结构化、可编辑、可复用的“计划建议语言”,既能帮助DBA保障关键查询执行的可预测性,又为开发测试和优化研究提供了强大工具。虽仍处于早期,带有一定尝试性质,但其丰富的设计思想、灵活的接口和完善的反馈机制,都为日后的数据库性能调优打开了新视野。

参考

pg_plan_advice: Plan Stability and User Planner Control for PostgreSQL?