Pg_hint_plan:强制 PostgreSQL 按你想要的方式执行查询计划

pg_hint_plan 提供什么

  • 该扩展允许用户将 PostgreSQL 的规划器引导到特定计划(连接、索引等),而无需修改核心 PostgreSQL。
  • 它被认为尤其适用于:
    • 生产事故应急,当规划器选出灾难性计划时。
    • 研究/实验场景,你想固定某些计划选择,同时让规划器处理其余部分。
    • 从其他数据库迁移(例如通过 Babelfish)时,现有工作负载依赖 hint。

使用中的实际问题

  • hint table 接口被描述为很脆弱:
    • 匹配对空格敏感,可能静默失败。
    • 参数处理比较别扭;早期工具让迭代参数化查询很困难,不过新版 psql 有所帮助。
  • 该扩展通过改变计划成本来“强烈建议”某个计划;如果被提示的计划根本不可行,PostgreSQL 仍会选择别的方案。

争论:Hints 是好还是坏?

  • 担忧:
    • 随着数据和 PostgreSQL 版本演进,hint 可能把次优计划固定下来。
    • 开发者很少回头检查被 hint 的查询;技术债会不断累积。
    • 核心开发者的立场(如文中所述):与其给 SQL 加 hint,不如改进统计信息和优化器。
  • 反驳观点:
    • 生产环境里,可预测性往往比理论最优更重要;避免突然的计划回退至关重要。
    • 统计信息和规划器配置复杂、全局化且有风险;hint 是局部的,对单个查询更容易推理。
    • PostgreSQL 的统计信息和优化器在大规模、以及相关性强或数据倾斜明显的场景下已知存在弱点;一些问题多年未解决。
    • hint 被比作“内联汇编”:作为默认方案很糟,但在罕见边缘情况下极其有价值。

替代方案与调优方法

  • 建议的不使用 hint 的修复方式:
    • VACUUM ANALYZE,以及调优 autovacuum。
    • 提高每列统计目标,或使用扩展/自定义统计信息。
    • 使用 SET LOCAL 限定范围调整规划器配置(join_collapse_limit、cost 参数)。
    • 调整模式/索引设计(复合索引或部分索引),更好地支持常见查询。

规划器痛点与示例

  • 有多起报告显示,LIMIT + ORDER BY + WHERE 查询会选出非常差的计划,尤其是在列之间存在相关性或数据倾斜时。
  • 对“灾难性计划翻转”到底有多常见存在分歧,但普遍共识是它们确实会发生,尤其是在超大表上。
  • 有人认为,这使得 PostgreSQL 在生产环境中“很危险”,因为缺少可靠的方法来固定或覆盖计划。