@@ -6,7 +6,7 @@ title: Cascade Optimizer(查询优化器)
66
77优化器(Optimizer)是数据库中用于把逻辑计划转换成物理执行计划的核心组件,很大程度上决定了一个系统的性能。查询优化的本质就是对于给定的查询,找到该查询对应的正确物理执行计划并且是最低的"代价(cost)"。
88
9- 在 MiniOB 中,查询优化器目前将优化分为两个阶段(基于规则的优化和基于代价的优化)。本文主要介绍基于代价的查询优化器实现( Cascade Optimizer), 其代码实现主要位于 ` src/observer/optimizer/cascade ` 。
9+ 在 MiniOB 中,查询优化器目前支持两种优化模式:基于规则的优化(RBO)和基于代价的优化(CBO)。两者都统一在 Cascade Optimizer 框架中实现,通过 ` use_cascade ` 配置项来选择使用哪种模式。本文主要介绍 Cascade Optimizer 的实现, 其代码实现主要位于 ` src/observer/sql /optimizer/cascade ` 。
1010
1111## 基本概念
1212
@@ -18,20 +18,31 @@ title: Cascade Optimizer(查询优化器)
1818这里的Expression(表达式)表示一个带有零或多个Input Expression(输入表达式)的Operator,同样可以分为Logical Expression(逻辑表达式)和 Physical Expression(物理表达式)。
1919例如对于 TableScan 算子来说,TableScan 算子本身就可以理解为是一个 Expression(不带输入表达式);对于 Join 算子来说,Join 算子以及其子节点一起构成一个 Expression。
2020
21- MiniOB 当前的实现中为每个 ` OperatorNode ` 增加了一个成员变量 ` vector< OperatorNode*> general_children_; ` ,可以认为这里的 Expression 也对应到 MiniOB 中的 ` OperatorNode ` 。
21+ 在 MiniOB 的 Cascade Optimizer 中,Expression 通过 ` GroupExpr ` (M_EXPR)来表示。 ` GroupExpr ` 包含一个 ` OperatorNode ` (算子)和一组子 Group 的 ID( ` child_group_ids ` ),而不是直接存储子 OperatorNode。这种设计使得多个等价的 Expression 可以共享相同的子 Group,从而避免重复计算 。
2222
2323### Group
2424Group 是一组逻辑等效的逻辑和物理表达式,产生相同的输出。
2525例如对于 ` SELECT * FROM A JOIN B ON A.id = B.id JOIN C ON C.id = A.id; ` 来说,其输出结果为 A,B,C 三个表根据 Join 条件进行 Join 的结果。逻辑表达式就可能包括 ` (A Join B) Join C ` ,` A Join (B Join C) ` ;物理表达式就可能包括` (A Hash Join B) Nested Loop Join C ` ,` (A Hash Join B) Hash Join C ` 等。
2626在 MiniOB 中,Group 对应的实现位于 ` src/observer/sql/optimizer/cascade/group.h ` 。
2727
28- ### M_EXPR
29- M_EXPR 是 Expression(表达式) 的一种紧凑形式。 输入是 Group 而不是 Expression。因此可以理解为, M_EXPR 包含多个 Expression。在 Cascade 中,所有搜索都是通过 M_EXPR 完成的。
30- 在 MiniOB 中,M_EXPR 对应的实现位于 ` src/observer/sql/optimizer/cascade/group_expr.h ` 。
28+ ### M_EXPR (GroupExpr)
29+ M_EXPR(在 MiniOB 中实现为 ` GroupExpr ` )是 Expression(表达式)的一种紧凑形式。M_EXPR 包含一个 Operator(算子)和一组子 Group 的 ID,而不是直接包含子 Expression。这种设计的优势在于:
30+ - ** 共享子表达式** :多个等价的 Expression 可以共享相同的子 Group,避免重复计算
31+ - ** 紧凑表示** :通过 Group ID 引用子节点,而不是直接存储子节点,节省内存
32+ - ** 等价性检测** :通过 Group 机制,可以自动识别等价的表达式
33+
34+ 在 Cascade 中,所有搜索都是通过 M_EXPR 完成的。在 MiniOB 中,M_EXPR 对应的实现位于 ` src/observer/sql/optimizer/cascade/group_expr.h ` 。
3135
3236### Rule(规则)
3337规则是将 Expression 转换为逻辑等价表达式。包含了Transformation Rule 和 Implementation Rule。其中,Transformation Rule 是将逻辑表达式转换为逻辑表达式;Implementation Rule 是将一个逻辑表达式转换为物理表达式。
34- 在 MiniOB 中,Rule 对应的实现位于 ` src/observer/sql/optimizer/cascade/rules.h ` ,目前 MiniOB 只实现了 Implementation Rule。
38+
39+ ** 规则应用策略** :在 MiniOB 的 Cascade Optimizer 中,规则应用采用** 全量应用** 策略:
40+ - ** CBO 模式** :收集所有匹配的规则,为每个规则创建 ` APPLY_RULE ` task,所有匹配的规则都会被应用
41+ - ** RBO 模式** :遍历所有规则,对每个匹配的规则都进行应用,直到没有新的逻辑表达式生成
42+
43+ 这种全量应用策略确保了所有可能的优化机会都被探索,从而生成更多的候选计划(CBO)或应用更多的优化规则(RBO)。
44+
45+ 在 MiniOB 中,Rule 对应的实现位于 ` src/observer/sql/optimizer/cascade/rules.h ` 。目前 MiniOB 已经实现了 Transformation Rule(如谓词下推、谓词重写、表达式简化)和 Implementation Rule(如逻辑算子到物理算子的转换)。
3546
3647### Memo(在 Columbia 中也叫做 Search Space)
3748Memo 用于存放查询优化过程中所有枚举的计划的数据结构,利用 Memo 来避免生成重复的计划生成。
@@ -49,7 +60,10 @@ while task_list is not empty
4960 perform task
5061```
5162
52- 在cascade(columbia)中,task共分为5种, 其整体调度的流程图如下:
63+ 在 MiniOB 的 Cascade Optimizer 中,task 共分为 6 种,根据优化模式(RBO 或 CBO)使用不同的 task:
64+
65+ ** CBO 模式(Cost-Based Optimization)** :
66+ 使用异步任务调度,task 调度的流程图如下:
5367```
5468 optimize()
5569 │
@@ -75,27 +89,55 @@ while task_list is not empty
7589 │ │
7690 └─────────────┘
7791```
78- * O_GROUP:根据优化目标,对一个 Group 进行优化,即遍历 Group 中的每个 M_EXPR,为logical M_EXPR 生成一个 O_EXPR task,为 physical M_EXPR 生成一个 O_INPUTS task。
7992
80- * O_EXPR:对一个logical M_EXPR 进行优化,对于该 logical M_EXPR,如果存在可以应用的规则,则生成一个 APPLY_RULE task。
93+ ** RBO 模式(Rule-Based Optimization)** :
94+ 使用同步递归,通过 ` OPTIMIZE_RBO_GROUP ` task 直接应用规则。
95+
96+ ### Task 类型说明
97+
98+ * ** O_GROUP** (CBO):根据优化目标,对一个 Group 进行优化,即遍历 Group 中的每个 M_EXPR,为 logical M_EXPR 生成一个 O_EXPR task,为 physical M_EXPR 生成一个 O_INPUTS task。
99+
100+ * ** O_EXPR** (CBO):对一个 logical M_EXPR 进行优化,对于该 logical M_EXPR,如果存在可以应用的规则,则生成一个 APPLY_RULE task。
81101
82- * E_GROUP:为 Group 中的每一个 logical M_EXPR 生成一个 O_EXPR task。
102+ * ** E_GROUP** (CBO) :为 Group 中的每一个 logical M_EXPR 生成一个 O_EXPR task。
83103
84- * APPLY_RULE:应用具体的优化规则,从逻辑表达式转换到逻辑表达式,或者从逻辑表达式转换为物理表达式。如果产生逻辑表达式,则生成一个 O_EXPR task;如果产生物理表达式,则生成一个 O_INPUTS task。
104+ * ** APPLY_RULE** (CBO) :应用具体的优化规则,从逻辑表达式转换到逻辑表达式,或者从逻辑表达式转换为物理表达式。如果产生逻辑表达式,则生成一个 O_EXPR task;如果产生物理表达式,则生成一个 O_INPUTS task。
85105
86- * O_INPUTS:对物理表达式的代价进行计算,在此过程中需要递归地计算子节点的代价。
106+ * ** O_INPUTS** (CBO) :对物理表达式的代价进行计算,在此过程中需要递归地计算子节点的代价。
87107
88- 在 MiniOB 中,5 种类型的 task 位于 ` src/observer/sql/optimizer/cascade/tasks ` 目录下,
89- Cascade Optimizer 的入口函数为 ` src/observer/sql/optimizer/cascade/optimizer.h::Optimizer::optimize ` 。
108+ * ** OPTIMIZE_RBO_GROUP** (RBO):使用同步递归的方式,对 Group 应用 transformation rules 和 implementation rules。先应用 transformation rules 生成逻辑表达式,然后应用 implementation rules 生成物理表达式。不进行代价计算,只保留最后一个(最变换的)物理表达式。未来会跳过需要代价估算的规则(如 IndexScan、HashJoin 等)。
109+
110+ 在 MiniOB 中,所有 task 类型位于 ` src/observer/sql/optimizer/cascade/tasks ` 目录下,Cascade Optimizer 的入口函数为 ` src/observer/sql/optimizer/cascade/optimizer.h::Optimizer::optimize ` 。
111+
112+ ### RBO 与 CBO 的区别
113+
114+ | 特性 | RBO | CBO |
115+ | ------| -----| -----|
116+ | 任务调度 | 同步递归 | 异步任务调度 |
117+ | 执行模式 | 先应用规则,再按需优化新节点 | 先应用规则,再按需优化新节点 |
118+ | 候选探索 | 只保留最后一个(最变换的)逻辑/物理表达式 | 探索多个候选计划 |
119+ | 代价计算 | 不计算代价 | 计算代价,选择最优 |
120+ | 适用场景 | 简单查询,快速优化 | 复杂查询,需要精确代价估算 |
121+
122+ 两者都使用相同的规则集(Transformation Rules 和 Implementation Rules)。目前 RBO 还没有区分哪些规则需要代价计算,但未来可能跳过依赖代价估算的规则(如 IndexScan、HashJoin 等),因为 RBO 不进行代价计算,无法判断这些规则生成的计划是否更优。
90123
91124## 如何为 Cascade 添加新的算子转换规则
92125
931261 . 添加逻辑算子和物理算子的定义,可参考` src/observer/sql/operator/table_get_logical_operator.h ` 和 ` src/observer/sql/operator/table_scan_physical_operator.h `
941272 . 添加逻辑算子到物理算子的转换规则,可参考` src/observer/sql/optimizer/implementation_rules.h::LogicalGetToPhysicalSeqScan `
951283 . 在 ` src/observer/sql/optimizer/rules.h ` 中的 ` RuleSet ` 中注册相应的转换规则。
96129
130+ ## 优化模式选择
131+
132+ MiniOB 通过 ` use_cascade ` 配置项来选择优化模式:
133+ - ` use_cascade = true ` :使用 CBO 模式,进行代价估算并选择最优计划
134+ - ` use_cascade = false ` :使用 RBO 模式,按规则顺序应用,不进行代价估算
135+
136+ 两种模式都统一在 Cascade Optimizer 框架中,使用相同的规则集和 Memo 结构,只是执行方式和候选选择策略不同。
137+
97138## WIP
98- 1 . 将现有的基于规则的逻辑计划到逻辑计划的转换加入到 cascade optimizer 中。
99- 2 . 实现 Apply Rule 中的 Expr binding。
100- 3 . 实现 property enforce。
101- 4 . 统计信息收集更多信息。
139+ 1 . 实现 Apply Rule 中的 Expr binding。
140+ 2 . 实现 property enforce。
141+ 3 . 统计信息收集更多信息。
142+ 4 . 优化 RBO 模式的规则应用顺序。
143+ 5 . 在 RBO 模式中区分并跳过需要代价计算的规则(如 IndexScan、HashJoin 等)。
0 commit comments