这是我参与「第四届青训营 」笔记创作活动的的第1天
每次上课对我来说都是一种新的认知,每次上课收获一点点就已经足够了
大数据体系下的SQL
一个SQL是如何执行的?
理解今天的主题SQL Optimizer就需要知道一条SQL语句是如何执行的?
Parser
首先当我们写好一段SQL代码,他会由一段文本变成抽象的语法树结构(Abstract Syntax Tree)便于计算机去分析,其中涉及词法分析和语法分析,对一条SQL语句,先将其拆分字符串,提取关键字,字符串,数值等,再把词条按照定义的语法规则组装成抽象语法树结构。
Analyzer
Analyzer的任务是将AST转化成逻辑计划树(Logic Plan),首先会将库/表的元信息绑定,再检查SQL是否合法,比如是否访问的库、表、列是否存在,列的数据类型是否正确,最后将AST转化成逻辑计划树。
逻辑计划树就是利用逻辑将一个SQL语句拆分成一条条查询和计算,分步骤得到最后的结果。树中每一个节点对应一个算子,是对数据集合的一些操作,比如过滤,排序,聚合,连接,这些数据从子节点流向父节点,是一种逻辑的表示而不是具体的实现。
Optimizer
这是我们这次课的核心内容!
优化器的作用就相当于gcc编译c程序的编译级别,为了让SQL语句运行的效率更高,在优化器的作用下,找到一个正确且执行代价最小的执行计划!
如果一个SQL Join的表更多,数据量就要不断增大,查询优化的意义就越大,不同的执行方法可能带来的性能差异有成百上千倍。
物理执行计划
当一个逻辑计划树进入优化器之后,优化器的输出是一个分布式的物理执行计划(Distributed Plan Fragments)
首先我们可以得到单机版的执行计划,所以分布式物理执行计划的目标就是协同起来在单机的基础上最小化数据移动和本地化扫描,生成一个PlanFragment树。
一个 PlanFragment 封装了在一台机器上对数据集的操作逻辑。每个 PlanFragment 可以在每个 executor 节点生成 1 个或多个执行实例,不同执行实例处理不同的数据集,通过并发来提升查询性能。
将本地计划分布式化的方法是增加Shuffle算子,执行计划树会以Shuffle算子为边界拆分PlanFragment。
什么是Shuffle算子? 在Spark中Shuffle算子这样定义:把不同节点的数据拉取到同一个节点的过程就叫做Shuffle
Executor
Executor 按照物理执行计划扫描和处理数据,充分利用机器资源(CPU 流水线,乱序执行,cache,SIMD)
常见的查询优化器
这部分内容在学校的数据库课程中有所涉及,但是不作为考点所以不曾关注过,没想到居然是SQL执行过程中的核心内容。
RBO Rule-Based Optimizer
基于关系代数公式对逻辑计划树进行简化计算,很大程度上是基于启发式规则(经验归纳)。
这些关系代数等价变化基于交换律、结合律、传递性,满足以下几个基本原则:更少更快的数据读写(IO)、更少更快的数据传输(网络)、更少更快的数据处理(CPU和内存)。
在PPT中列举了集中常见的RBO操作
- 列剪裁:在算子中不需要用上的列,优化器在优化的过程中没有必要保留它们,节约IO资源
- 谓词下推:谓词下推将查询语句中的过滤表达式计算尽可能下推到距离数据源最近的地方,以尽早完成数据的过滤,进而显著地减少数据传输或计算的开销。
- 传递闭包:查询语句中的过滤表达式可以利用等价传递性传递性,完成被传递列数据的过滤,减少数据传输或计算的开销。
- Runtime filter:在SQL运行的时候可以得到一些数据范围从而对还未完成的节点进行过滤,减少计算的开销
CBO Cost-Based Optimizer
CBO通过一个代价模型估算执行计划的代价,最后通过贪心或者动态规划算法选择代价最小的计划执行。
执行计划的代价等于所有算子的执行代价之和,算子的代价取决于很多因素(CPU、内存、IO、网络),在叶子节点上的代价可以通过原始表的统计信息得到,中间算子根据其子节点的代价通过一些计算规则得出。
原始表的统计信息包含:
- 表:行数、行平均大小、占用字节
- 列:min、max、num nulls、num not nulls、num distinct value、histogram
最后根据以上信息推导出下面两个统计信息:
- 选择率(Selectivity):对于某个过滤条件,会从表中获得多大比例的数据
- 基数(Cardinality):算子需要处理的行数
准确的Cardinality远比代价模型本身重要!
RBO和CBO的比较
- RBO实现简单,优化速度快但不保证得到最优的执行计划
- CBO使用贪心或者动态规划算法得到最优执行计划,使用代价模型和统计信息估算执行计划的代价,在大数据场景下CBO对查询优化非常重要