这是我参与「第四届青训营 」笔记创作活动的第 4 天!
1、 常见的查询优化器
查询优化器分类
Top-down Optimizer
-
从目标输出开始,由上往下遍历计划树,找到完整的最优执行计划
-
例子:Volcano/Cascade,SQLSever
Bottom-up Optimizer
-
从零开始,由下往上遍历计划树,找到完整的执行计划
-
例子:System R,PostgreSQL,IBM DB2
RBO(Rule-based Optimiser)
-
基于规则优化,采用指定的等价关系代数表达式进行优化。
-
基于启发式规则
-
会访问表的元信息,不会设计具体的表数据
CBO(Cost-based Optimiser)
- 使用模型估算执行计划的代价,选择代价最小的执行计划
*RBO
关系代数
- 运算符:Select Project Join Rename Union
- 等价变换:结合律、交换律、传递性
优化规则
-
读取数据更少更快(I/O)
-
传输数据更少更快(Network)
-
处理数据更少更快(CPU & Memory)
一些优化规则:
-
列裁剪 : 仅扫描所需要的部分列,而不是扫描所有
-
谓词下推
-
传递闭包 :根据表达式等价关系,过滤条件,推导出一个新的过滤条件
-
Runtime Filter
对一个join如果能在查询端提早过滤不必要数据,可减少开销
- min-max的缺点:范围必须很紧密
-
- in-list:只需要扫描in-list里的数据。缺点:集合个数很多时,in-list也很大
-
- bloom filter:特性:大小不随集合大小改变,固定大小,给一个数可以判断在不在
实现上:
-
Pattern:定义了特定结构的 Operator 子树(结构)
-
Rule:定义了如何将其匹配的节点替换(Substitute)为新形态,从而生成新的、等价的Operator 树(原地替换)
-
优化器搜索过程被抽象为不断匹配 Pattern 然后应用 Rule 转换,直到没有可以匹配的 rule
局限性:
- 无法解决多表连接问题
- 无法确定和选择最优的分布式 Join/Aggregate 执行方式
*CBO
graph LR
统计信息+推导规则 --> 计算算子代价 --> 计算执行计划代价 -->执行计划枚举
执行计划的代价等于所有算子的执行代价之和
算子代价包含 CPU,cache misses,memory,disk I/O,network I/O 等代价
-
和算子的统计信息有关,比如输入、输出结果的行数,每行大小等
-
叶子算子 scan:通过统计原始表数据得到
-
中间算子:根据一定的推导规则,从下层算子的统计信息推导得到
-
和具体的算子类型,以及算子的物理实现有关(e.g. hash join vs. sort join)
-
基表统计信息
- 表或者分区级别:行数、行平均大小、表在磁盘中占用了多少字节等
- 列级别:min、max、num nulls、num、not nulls、num、distinct value(NDV)、histogram 等
推导统计信息
- 选择率(selectivity) :对于某一个过滤条件,查询会从表中返回多大比例的数据
- 基数(cardinality) :基本含义是表的 unique 行数,在查询计划中常指算子需要处理的行数
使用贪心或者动态规划算法寻找最优执行计划
2、查询优化器社区开源实践
-
Apache Calcite
-
Orca
-
Volcano/Cascade 框架
- Memo
- AND/OR Graph
- Expression group
- Group expression
- Pattern
- Rule
- Branch-and-Bound Pruning
- Winner
3、前沿趋势
-
存储计算分离
-
HSAP, HTAP, HTSAP
-
Cloud Native, Serverless
-
数据仓库,数据湖,湖仓一体,联邦查询
-
智能化:AI4DB,DB4AI