本文整理于 HOW 2026 演讲内容,演讲者:杨向博,PostgreSQL ACE。
在数据库系统的日常运维中,SQL执行计划“跑偏”是最令DBA头疼的问题之一。明明一条SQL语句,不加LIMIT时执行飞快,加了LIMIT反而慢了几千倍;明明通过HINT指定了索引,优化器却置若罔闻,走了顺序扫描。这些看似“降智”的行为背后,究竟隐藏着怎样的机制?
本文基于HOW 2026开源生态大会暨PostgreSQL高峰论坛的主题分享,系统剖析PostgreSQL优化器在代价比较与路径选择中的核心逻辑,解读PG 18在路径禁用机制上的重大变革,并展望AI驱动执行计划自动优化的未来方向。
在PostgreSQL中,有时会出现一种反直觉的现象:带LIMIT的查询,执行耗时反而比不带LIMIT的查询更久。

某实际场景中,不带LIMIT的查询执行仅需 0.1毫秒,而带LIMIT的查询却耗时 3秒以上——差距高达数万倍。
根本原因在于:PostgreSQL的LIMIT算子没有充分考虑真实的数据分布,在代价预估(Cost Estimation)环节选错了索引,导致回表时间急剧增加。
在PG 17及更早版本中,使用pg_hint_plan插件指定索引时,会出现一种令人费解的现象——明明通过HINT要求走索引扫描,执行计划却依然走了并行顺序扫描。
/* 通过HINT指定走特定索引 *//*+ IndexScan(tbl tbl_name_idx) */SELECT ... FROM tbl WHERE name = 'xxx';
执行结果显示走了 并行顺序扫描,HINT仿佛完全被忽略。
这一问题的根源,要从PG优化器的代价比较机制说起。
在分析具体问题之前,首先需要纠正一个关于CBO(Cost-Based Optimizer,基于代价的优化器)的常见误区。
很多人认为:优化器生成所有可能的执行路径后,通过比较最终总代价(Total Cost),选出代价最小的路径作为最优执行计划。
但实际上并非如此。
在PG中,路径的生成与淘汰是
逐层进行的。在
add_path()函数中,新生成的路径会与已有路径进行比较,不具备显著优势的路径会被
立即淘汰,而不会等到所有路径生成完毕后再做决策。

PG优化器中存在一个名为
COST_EPSILON的模糊比较系数,默认值为
1%。
其核心逻辑是:当两条路径的 总代价(Total Cost) 差异在1%以内时,优化器认为二者“代价相等”,此时会进一步比较 启动代价(Startup Cost),取启动代价更小的路径。
回到HINT失灵的案例:

使用HINT指定索引扫描时,pg_hint_plan插件通过设置一个巨大的
disable_cost值(100亿级别,定义为
DBL_MAX/100000.0)来“惩罚”其他路径,试图让目标路径在代价比较中胜出。
然而,当所有路径的代价都被加上一个巨大的常量后,原本存在的代价差异被 压缩进1%的模糊区间内。优化器无法分辨优劣,转而比较启动代价,最终可能选出非预期的路径——比如并行顺序扫描。
这就是为什么HINT在极端代价偏差下会“失灵”的根本原因。
再看另一个典型案例。
一条涉及外部表关联的查询,优化器默认选择了 Nest Loop Join,执行耗时高达 244秒。
通过
SET enable_nestloop TO OFF强制禁用Nest Loop后,优化器选择了
Hash Join,执行耗时骤降至
287毫秒——差距近千倍。

进一步分析执行计划发现:
| 路径 | Total Cost | Startup Cost | 执行耗时 |
|---|---|---|---|
| Nest Loop | 232.45 | 200.00 | 244秒 |
| Hash Join | 232.44 | 216.13 | 287毫秒 |
仔细观察Total Cost:232.45与232.44,差距仅 0.01,占总代价的约 1/23200 ≈ 0.004%,远小于1%的阈值。
两条路径的总代价差异在1%以内,被优化器视为“相等”。随后比较启动代价(Startup Cost):Nest Loop的启动代价为200,Hash Join为216.13——Nest Loop胜出。
于是,Hash Join路径在
add_path()阶段被直接淘汰,根本没能进入最终的路径候选集。
这就是1%模糊比较导致的“错杀”悲剧。
PG的代价(Cost)数值通常保留到小数点后两位(百分位)。最小可表示的代价差异即为0.01。
假设两条路径的总代价在100左右,0.01的差异恰好对应约 0.01%。而1%的阈值是为了规避浮点运算误差带来的不确定性判断——当差异小于1%时,优化器认为它们在统计误差范围内“等价”,转而比较其他维度(如启动代价)。
问题在于: 真实的执行性能差异,与优化器代价预估的百分比差异,并不成正比。
232.44与232.45只差0.01,但实际执行时间却差了近千倍——这充分暴露了优化器代价模型与实际执行之间的偏差。
针对上述问题,PG 18引入了一项重大改进——路径禁用机制。
该改进由Robert Haas(社区Core Team成员)主导提交,在PG 18的第一个版本中即已合入。郭峰(Richard Guo)等中国贡献者也参与了相关讨论。
旧逻辑(PG 17及以前) :
disable_cost值来“惩罚”非目标路径新逻辑(PG 18+) :
Path结构体中新增整型变量
disable_nodesdisable_cost逻辑disable_nodes在路径比较中拥有
一票否决权
disable_nodes是一个整型计数器,遵循
层层累积与传递的原则:
SET enable_seqscan TO OFF时,顺序扫描路径的
disable_nodes从默认的0变为1disable_nodes值向上层层传递并
递增累积disable_nodes的值,
越小越优disable_nodes大于另一条,直接淘汰,不再比较代价-- 禁用顺序扫描SET enable_seqscan = OFF;-- 对应路径的 disable_nodes = 1-- 禁用Nest LoopSET enable_nestloop = OFF;-- 对应路径的 disable_nodes = 1-- 如果一条路径同时使用了顺序扫描和Nest Loop-- 其 disable_nodes = 1(scan层)+ 1(join层)= 2-- 在路径比较中会优先被淘汰
在
compare_path_costs_fuzzily()函数中,比较顺序发生了变化:
旧逻辑(PG 17及以前) :
新逻辑(PG 18+) :

在PG 18中,同样的HINT指定索引扫描:
/*+ IndexScan(tbl tbl_name_idx) */SELECT ... FROM tbl WHERE name = 'xxx';
执行计划精准地走向了指定索引,耗时从3秒以上降至 0.1毫秒。
执行计划中会显示
Disabled Nodes = true标记,清晰指示哪些路径被禁用。Cost数值不再被巨大常量扭曲,回归正常范围。

| 维度 | PG 17及以前 | PG 18+ |
|---|---|---|
| 核心机制 | disable_cost(粗暴加价) | disable_nodes(精确禁用) |
| 比较优先级 | Total Cost → Startup Cost | disable_nodes → Total Cost → Startup Cost |
| HINT成功率 | 极端代价下会失效 | 100%精准命中 |
| 代价扭曲 | 巨大常量扭曲模糊比较 | 无扭曲,完全隔离 |
| 人为干预 | 偶尔不可靠 | 指哪打哪 |
即便有了PG 18的精确禁用机制,优化器自身的代价预估偏差仍然客观存在。偏差的根源主要包括:
传统的CBO正面临来自AI方向的挑战与补充—— 学习型优化器应运而生。
其核心思路是:利用机器学习/强化学习技术,通过HINT作为干预手段,持续采集执行反馈(Feedback),自动学习不同负载下的最优执行计划。
实验测试(基于Babylon测试集)显示:
更长远来看,数据库执行计划的治理应走向类似 Oracle SPM(SQL Plan Management,SQL计划管理) 的方向:
这并不是要替代传统的CBO优化器,而是 在CBO的基础上增加一个AI辅助决策层。当优化器的代价预估与实际执行出现偏差时,AI层可以介入干预,通过Hint机制“拨正”执行计划。两者相辅相成——CBO负责快速的路径生成与基础代价估算,AI层负责在代价模型失准时进行精准纠偏,共同构建更智能、更稳健的执行计划管理系统。
PostgreSQL 18引入的
disable_nodes禁用节点机制,是执行计划干预能力的一次
质的飞跃。它从根本上解决了传统
disable_cost粗暴加价模式导致的HINT失效问题,让DBA和开发者能够
精准、可靠地控制执行计划。
这一改进的意义远超技术层面——它意味着PG在执行计划治理的确定性上迈出了关键一步,为解决因优化器代价偏差导致的性能问题提供了坚实的基础设施。
与此同时,AI驱动的学习型优化器正在为未来打开新的可能。在不远的将来,数据库或许能够 自动学习、自动优化,在CBO的基础上叠加AI辅助决策层,让执行计划的选择既能继承CBO的高效路径生成能力,又能通过AI层精准纠偏,实现真正的“智能优化”。
届时,DBA的工作重心将从“被动救火”转向“主动治理”,这将是数据库运维的又一次范式转移。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70043484/viewspace-3181746/ ,如需转载,请注明出处,否则将追究法律责任。