SQL Optimizer 解析 | 青训营笔记

149 阅读8分钟

这是我参与「第四届青训营 」笔记创作活动的的第1天。

一、本堂课重点内容:

1.1 大数据体系和SQL

介绍大数据体系和SQL的处理流程,重点介绍SQL在分布式环境下的处理

1.2 常见的查询优化器

介绍查询优化器的分类,重点介绍RBO和CBD的原理

1.3 社区开源实践

介绍查询优化器在社区的开源实践,重点介绍Apache Calcite项目

1.4 前沿趋势

介绍SQL引擎的前沿趋势,重点介绍AI和DB的结合

二、详细知识点介绍:

2.1 SQL的处理流程

graph LR
Input--SQL-->Parser
Parser--AST--> Analyzer
Analyzer--Logical Plan-->Optimizer
Optimizer--Physical Plan-->Executor
  • 每个SQL语句实际上就是按照规定格式的字符串,输入进去之后毫无疑问首先进行的就是要理解这条字符串,那么就用到了Parser,这个解析器要完成两个工作词法分析和语法分析,首先进行的就是词法分析,将这个字符串进行拆分,得到关键词、数值常量、字符串常量、运算符号等,然后存储在token中,之后用得来的token进行语法分析,组成AST node,最终得到一个抽象语法树即AST,简单来说就是将这个SQL语句字符串拆开来进行分门别类方便后续操作进行。
  • 获得AST之后,就轮到了Analyzer大显身手,这个分析器要检查并绑定SQL语句中指定的数据库、表、列等元信息,还要检查SQL语句写的对不对,符不符合要求,有个合法性检查,没问题后就将AST转化为Logical Plan即逻辑计划树。

所谓逻辑计划树,可以理解为逻辑地描述一个 SQL 如何一步步地执行查询和计算,最终得到执行结果的一个分步骤地计划。树中每个节点是是一个算子,定义了对数据集合的计算操作(过滤,排序,聚合,连接),边代表了数据的流向,从孩子节点流向父节点。之所以称它为逻辑的,是因为算子定义的是逻辑的计算操作,没有指定实际的算法,比如对于逻辑的排序算子,逻辑计划树里没有指定使用快排还是堆排。

  • 之后就是查询优化器要干的事情了,要查询的结果SQL语句已经定下来了,但是数据库怎么去得到这个结果没有规定,所以我们肯定是希望在得到同样结果的同时,所花费的开销要尽量的小,它的目标就是找到一个正确且执行代价最小的物理执行计划即Physical Plan,优化器的输出是一个分布式的物理执行计划。

分布式物理执行计划的目标是在单机 Plan 的基础上最小化数据移动和最大化本地 Scan,生成 PlanFragment 树。

一个 PlanFragment 封装了在一台机器上对数据集的操作逻辑。每个 PlanFragment 可以在每个 executor 节点生成 1 个或多个执行实例,不同执行实例处理不同的数据集,通过并发来提升查询性能。

Plan 分布式化的方法是增加 shuffle 算子,执行计划树会以 shuffle 算子为边界拆分为PlanFragment。

  • 最后一步就是执行啦,Executor 按照物理执行计划扫描和处理数据,充分利用机器资源(CPU 流水线,乱序执行,cache,SIMD)

2.2 常见的查询优化器

关于RBO与CBO,有个形象的比喻:⼤数据时代到来以前,做生意或许凭借多年累计下来的经验(RBO)就能够很好的做出决策,跟随市场变化。 但是大数据时代,如果做生意还是靠以前凭经验做决策,而不是靠大数据、数据分析、数据挖掘做决策,那么就有可能做出错误的决策。 这也就是越来越多的公司对BI、数据挖掘越来越重视的缘故,像电商、游戏、电信等⾏业都已经⼤规模的应⽤。

2.2.1 RBO:基于规则的优化器

  • 基于关系代数等价规则对逻辑计划进行变换
  • 简单来说就是前人根据经验总结出各个访问路径的优先级,而这个优化器就是按照系统的特定规则选取优先级最高的访问路径,即依据关系代数等价规则转化为高优先级的访问路径
  • Pattern:定义了特定结构的 Operator 子树(结构)

  • Rule:定义了如何将其匹配的节点替换(Substitute)为新形态,从而生成新的、等价的Operator 树(原地替换

  • 优化器搜索过程被抽象为不断匹配 Pattern 然后应用 Rule 转换,直到没有可以匹配的 rule

2.2.2 CBO:基于代价的优化器

  • 使用一个模型估算执行计划的代价,选择代价最小的执行计划。
graph LR
原始表统计信息+推导规则 --> 算子代价计算规则
算子代价计算规则-->计算执行计划代价
计算执行计划代价-->执行计划枚举
  • 这边老师介绍了统计信息+推导规则和执行计划枚举
  • 统计信息:包含原始表统计信息和推导统计信息
    • 基表统计信息

      • 表或者分区级别:行数、行平均大小、表在磁盘中占用了多少字节等
      • 列级别:min、max、num nulls、num、not nulls、num、distinct value(NDV)、histogram 等
    • 推导统计信息

      • 选择率(selectivity) :对于某一个过滤条件,查询会从表中返回多大比例的数据
      • 基数(cardinality) :基本含义是表的 unique 行数,在查询计划中常指算子需要处理的行数

这里老师提到准确的基数,远比代价模型本身重要,主要是因为代价模型很可能是比较粗糙的无法完美契合,但准确的基数是可以得到一个比较好的执行计划的。

  • 推导规则:假设列和列之间是独立的,列的值是均匀分布
    • 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.0- fs(a)
    • 等于条件(x = literal)
      • literal < min && literal > max: 0
      • V1/NDV
    • 小于条件 (x < literal)
      • literal < min: 0
      • literal > max: 1
      • (literal - min) / (max - min)

最后的执行计划枚举,CBO一般使用贪心算法或者动态规划枚举所有执行的计划,选出执行代价最小的执行计划。

2.3 社区开源实践-Apache Calcite概览

Calcite 是一个用于优化异构数据源的查询处理的基础框架,它提供了标准的 SQL 语言、多种查询优化和连接各种数据源的能力,同时 Calcite 有着良好的可插拔的架构设计。

Apache Calcite核心架构.jpg

通过架构图我们可以看出,Calcite 最大的特点(优势)是它将 SQL 的处理、校验和优化等逻辑单独剥离出来,省略了一些关键组件,例如,数据存储,处理数据的算法以及用于存储元数据的存储库。其次 Calcite 做得最出色的地方则是它的可插拔机制,每个大数据框架都可以选择 Calcite 的整体或部分模块建立自己的 SQL 处理引擎,如 Hive 自己实现了 SQL 解析,只使用了 Calcite 的优化功能,Storm 以及 Flink 则是完全基于 Calcite 建立了 SQL 引擎。

Calcite框架运行阶段和2.1提到的四个阶段差不多,这里老师提到Apache Calcite内置RBO和CBO,RBO和上面2.2.1没什么区别,CBO就得详细介绍介绍了,Calcite CBO是基于Volcano/Cascade框架.

Cascade优化器是Volcano的后续版本,进行了一些优化。他们的主要思想都是通过规则枚举出所有的plan case,然后通过cost model 选出最优的plan。主要的不同点在于Volcano是先等价替换出所有的逻辑计划,然后计算物理计划。而Cascade是没有区分逻辑计划和物理计划,统一处理。个人认为Volcano类似于宽度优先搜索,Cascade类似于深度优先搜索

Volcano/Cascade的精髓:Memo、动态规划、剪枝

Memo 本质是 AND/OR Graph,通过共享相同的子树减少内存开销,记录搜索过的子树的最优执行计划(winner);

应用Rule搜索候选计划;

Branch-and-Bound Pruning:已搜索完成的物理计划的代价最小值成为 Cost Upper Bound。当新的搜索分支的代价高于它时,不需继续搜索。初始 Cost Upper Bound 可由优化器根据启发式规则估算。

2.4 前沿趋势-DATA+AI

  • AI4DB

    • 自配置:智能调参(OtterTuneQTune)、负载预测、负载调度
    • 自诊断和自愈合:软硬件错误、错误恢复和迁移
    • 自优化:统计信息估计( Learned cardinalities )、代价估计、学习型优化器(IBM DB2 LEO),索引推荐,视图推荐
  • DB4AI

    • 内嵌人工智能算法(MLSQL,SQLFlow)
    • 内嵌机器学习框架(SparkML, Alink, dl-on-flink )

三、实践练习例子:

【作业一】分布式计算系统 - 飞书文档 (feishu.cn)

四、课后个人总结:

  • 本章我觉得那个CBO的知识点还是很难理解的,自身基础不够,有些算法思想没有触类旁通不是很理解,需要花时间细细看一下。0.0
  • 还要写一点的话就是通过本课程的学习,对SQL Optimizer有了更深刻的认识,就是一开始那个SQL语句要进行Parser我就想到了我之前在用QT Creator链接数据库后,使用的SQL语句全部要存为QString,就是字符串,然后再交给解析器解析,还是挺有感触的(^▽^)

五、引用参考: