“优化器”到底是谁?PostgreSQL 和 MySQL 吵起来了
有一天,一位 PostgreSQL 内核开发者和一位 MySQL 内核开发者坐在一起喝茶,聊起 SQL 的执行流程。
PG 开发者说:“我们 PG 的流程很清晰:Parser → Analyzer → Rewriter → Planner → Executor。优化器就是 Planner,负责代价估算和物理优化。Rewriter 做的是逻辑重写,那是独立模块,不属于优化器。”
MySQL 开发者摇了摇头:“你这划分也太死板了。我们 MySQL 把 Parser 之后、Executor 之前的所有环节都叫优化器。谓词下推、子查询转换这些逻辑优化,当然是优化器的职责。优化器不只是选索引和 Join 顺序。”
PG 开发者不服:“逻辑优化怎么能叫优化器?那是重写!代码目录都分得清清楚楚。”
MySQL 开发者笑了:“那是你们 PG 有洁癖。我们觉得,只要能让查询跑得更快,都属于优化器的范畴。”
两人谁也说服不了谁。他们吵起来了。
但问题来了:他俩说的“优化器”,到底是不是同一个东西?
一、先别吵,我们看看大家公认的事实
不管哪个数据库,一条 SQL 从输入到执行,都要经过几个核心阶段:
| 阶段 | 核心职责 |
|---|---|
| Parser | 词法语法分析,检查 SQL 语法是否正确,生成抽象语法树(AST)。 |
| Analyzer | 语义分析:检查表、列、函数是否存在,类型推导,权限校验。 |
| Rewriter | 基于规则进行逻辑转换:视图展开、谓词下推、常量折叠、子查询提升等。 |
| Planner | 物理优化:基于统计信息,生成多种候选执行路径,用代价模型选择最优计划。 |
| Executor | 执行计划,返回结果。 |
这个流程在 PostgreSQL 和 MySQL 中都能找到对应,但关键的分歧在于:Rewriter 和 Planner 应该分开,还是应该统称为“优化器”?
二、PG 的立场:优化器就是 Planner,Rewriter 你给我出去
PostgreSQL 是一个“有强迫症”的数据库。它的代码目录就像一座规划严整的城市:
src/backend/
├── parser/ # Parser
├── rewrite/ # Rewriter(重写器)
├── optimizer/ # Optimizer(优化器)
│ ├── path/ # 路径生成
│ ├── plan/ # 计划生成
│ └── prep/ # 预处理
└── executor/ # Executor
在 PG 的世界里:
- Rewriter 住在自己的街区,负责视图展开、规则系统等逻辑转换。
- Optimizer(即 Planner)住在另一个街区,负责代价估算、路径选择、生成执行计划。
两个模块在代码上物理隔离,在调用时序上也一前一后。PG 开发者认为,逻辑优化(基于规则)和物理优化(基于代价)在原理和实现上完全不同,就应该分开。所以他们的结论非常坚定:
优化器 = Planner,只包含物理优化阶段。
如果你在 PG 的源码里找 optimizer 目录,里面是纯粹的代价估算和计划生成逻辑,找不到任何重写相关的代码。
三、MySQL 的立场:从逻辑到物理,都是我优化器的地盘
MySQL 则是典型的“实用主义者”。它的代码目录呈现出另一种画风:
sql/
├── sql_parse.cc # Parser
├── sql_optimizer.cc # 优化器主入口
├── optimizer/ # 优化器子模块
│ ├── cost.cc # 代价估算
│ ├── join_optimizer.cc # Join 优化
│ └── ...
└── executor/ # 执行器
在 MySQL 的体系里,没有独立的 Rewriter 模块。从语义分析结束之后,一直到执行计划生成,所有这些逻辑都被打包在“优化器”这个大框架里:
- 逻辑优化:子查询转换、常量折叠、谓词下推等规则,都在优化器内部完成。
- 物理优化:代价估算、索引选择、Join 顺序选择,同样是优化器的职责。
MySQL 开发者认为,无论是基于规则的重写,还是基于代价的选择,目的都是“让查询更快”。把它们统一在优化器模块里,逻辑更集中,模块间交互也更直接。所以他们的观点是:
优化器 = 逻辑优化 + 物理优化,涵盖 Rewriter 和 Planner 两个阶段。
四、为什么吵?两种设计哲学的正面交锋
这场“吵架”的背后,其实是两种数据库设计哲学的碰撞:
| 维度 | PostgreSQL | MySQL |
|---|---|---|
| 模块化风格 | 严格分层,模块物理分离 | 功能聚合,优化器内部统一 |
| 设计哲学 | 追求概念精确、职责单一 | 追求实用高效、便于集成 |
| 面向人群 | 内核开发者、学术研究 | 应用开发者、互联网场景 |
| 历史渊源 | 源于 POSTGRES 学术项目 | 源于开源互联网应用 |
PostgreSQL 的严格分层让代码更易维护,也更容易单独扩展某个阶段。例如,你可以单独修改 Rewriter 的规则系统而不影响优化器的核心逻辑。
MySQL 的统一框架则让逻辑优化和物理优化之间的交互更加直接。例如,在子查询转换时就可以直接考虑索引可用性,不需要在模块间传递多层中间表示。
这两种设计没有绝对的对错,只是不同的取舍。
五、吵归吵,对开发者到底有什么影响?
这场定义之争不只是理论上的争论,它直接影响我们怎么读源码、怎么调优、怎么写 SQL。
1. 阅读源码时
- PostgreSQL:想改重写规则,去
src/backend/rewrite/;想改代价模型,去src/backend/optimizer/。各找各家。 - MySQL:优化器相关逻辑都集中在
sql/optimizer/和sql/sql_optimizer.cc,逻辑重写和物理优化交织在一起,需要整体理解。
2. 性能调优时
- PostgreSQL:可以通过
rewrite阶段的规则系统(RULE)实现某些高级改写,但需要小心副作用。 - MySQL:优化器开关(
optimizer_switch)同时控制逻辑重写和物理优化,例如subquery_materialization_cost_based这类选项既涉及重写策略也涉及代价评估。
3. 技术面试时
当面试官问“优化器包含哪些阶段”时,如果你只回答“Planner”或只回答“Rewriter+Planner”,都可能显得片面。更专业的回答是:
从功能上讲,优化器通常包括逻辑优化(如重写)和物理优化(如代价选择)两个部分。但在具体实现上,不同的数据库有不同的划分方式,比如 PostgreSQL 把重写独立出来,优化器专指物理优化;而 MySQL 则把两者统一在优化器模块中。
这样既回答了核心问题,又体现了对数据库架构差异的理解。
六、谁赢了?其实没有标准答案
这场辩论到最后,两位开发者相视一笑。
PG 开发者承认:“你们 MySQL 把逻辑优化和物理优化放在一起,确实在工程实现上更紧凑。”
MySQL 开发者回应:“PG 的模块划分也确实清晰,扩展新功能时不用担心踩到其他模块的地盘。”
他们终于意识到,“优化器”这个词在不同语境下,本来就有不同的外延。
对于开发者来说,重要的不是站队,而是理解:当你听到“优化器”这个词时,对方站在哪个语境里。
下次再有人问你“优化器到底包含哪些阶段”,你可以笑着反问一句:
“你问的是 PostgreSQL 的优化器,还是 MySQL 的?”
更多推荐




所有评论(0)