这是我参与「第四届青训营」笔记创作活动的的第1天
SQL处理流程
1. Parser
String————————>token————————>AST(语法树)
词法分析 语法分析
2. Analyzer
AST——————————>Logical Plan(算子的排序而非如何执行)
Analyzer
(检查绑定元信息)
3. Optimizer
决定性能
目标:最小化网格数据传输
Logical Plan——————————>Physical Plan(Plan Fragment)
4. Executor
单机并行
多机并行
Optimizer分类
一、
- Top-down Optimizer 从目标输出开始,上至下遍历计划树,找完整最优执行计划
- Bottom-up Optimizer 从零开始,下至上,找完整执行计划
二、
- RBO
等价语义-->重写查询
基于启发式规则得到计划
会访问元信息,不涉及表数据 - CBO 使用一个模型估算执行计划的代价,基于代价择优
- 一半情况RBO可以找到最优解,无需CBO
- 另一半中大部分有CBO性能较高
- 大数据下CBO※
RBO
减少工作量,快,实现简单,基于经验得到(不保证最优)
一、
1. 关系代数
- 运算符(可拆分):select、 project、 join......
- 等价变换:结合律、交换律、传递性
2. 优化原则-少且快-按重要性可配比
- I/O
- Network
- cpu/Memory
3. 列裁剪
只扫描需要的 table student ————> student(sid, sname)
4. 谓词下推
谓词就是返回boolean值即true和false的函数,或是隐式转换为bool的函数
SQL中的谓词主要有 LKIE、BETWEEN、IS NULL、IS NOT NULL、IN、EXISTS
将过滤表达式尽可能移动至靠近数据源的位置,以使真正执行时能直接跳过无关的数据。 从计算进程下推到存储进程先行执行、以减少开销
谓词下推条件?
如果在表达式中含有不确定函数,整个表达式的谓词将不会被pushed,例如
select a.*
from a join b on a.id = b.id
where a.ds = '2019-10-09' and a.create_time = unix_timestamp();
因为unix_timestamp是不确定函数,在编译的时候无法得知,所以,整个表达式不会被pushed,即ds='2019-10-09'也不会被提前过滤。类似的不确定函数还有rand()等。1
5. 传递闭包
6. Runtime Filter
二、缺点
1. 单表扫描:
索引扫描(随机I/O)
vs 全表扫描(顺序I/O)
2. Join实现:
Hash Join
vs SortMergin Join
3.两表Hash Join
用小表构建Hash表-->如何识别小表
4.多表
最优?每种组合都探索?
CBO
解决RBO缺点
统计信息 + 推导规则 ——>计算算子代价、计划代价——>执行计划枚举
1.统计信息
- 统计信息的准确与否会影响CBO做出最优的选择
- 原始表统计信息(表/分区级别,列级别) ——> 推导统计信息(选择率、基数※)
- 收集方式:
-
- 写入时 (操作多,慢,影响写入效率)
-
- 手动执行 (执行前的数据是过时的)
-
- 动态采样 (select count(*) from table )
-
2. 推导规则
列独立、值均匀分布 (此假设与实际很不符-->指定或识别相关联的列、直方图)
- and : fs(a and b) = fs(a) * fs(b)
- or : fs(a or b) = fs(a) + fs(b) - fs(a) * fs(b)
- not : fs(not a) = 1 - fs(a)
- x = i : i < min && i > max ? 0 : 1/NDV (利用均匀分布)(NDV不同数的个数)
- x < i : i < min --> 0 ; i > max --> 1 ; (i - min)/(max - min) (利用均匀分布得到选择率)
3.执行计划枚举
贪心/动规 (比较代价)
社区开源实践
参考文献: