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 在生产环境中“很危险”,因为缺少可靠的方法来固定或覆盖计划。