1. SQL Optimizer 解析 | 青训营笔记

257 阅读5分钟

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

1. 大数据体系和SQL

1.1. 大数据体系和SQL

大数据体系 左侧为大数据应用层次; 中间为大类更细的划分; 右侧为工程中的组件, 更好的服务管理系统

为什么是SQL?

  1. SQL用户多, 语法简单
  2. 很多系统都提供SQL接口

SQL是大数据的入口

1.2. SQL处理有流程

SQL处理有流程

1.1.1. Parser

  • String -> AST(Abstract Syntax Tree)
    • 词法分析: 将输入字符换进行分词, 识别其中的关键字, 变量, 常量和运算符等(Token)
    • 语法分析: 将词法分析得到的分词(token)转换为AST的node, 最终组成一颗AST
    • AST
  • 实现: 递归下降(ClickHouse), Flex和Bison(PostgreSQL), JavaCC(Flink), Antlr(Presto, Spark)

1.1.2. Analyser和Logical Plan

  • Analyzer
    • 检查数据库中的变量名是否正确
    • 检查SQL函数中输入参数是否正确
    • 将AST转换为Logical Plan
  • Logical Plan
    • 逻辑性的描述所有的SQL操作
    • 每一步操作都是一个算子(operator)
    • Logical Plan
      • left-deep tree: join算子右侧必须为表

1.1.3. 查询优化

  • 为什么要做查询优化
    • SQL声明式语言, 只能按命令执行, 没有优化功能
    • 大数据场景下, Join表非常多, 数据量大的情况下, 不同执行方式性能相差千百倍
  • 优化目标
    • 正确执行, 代价最小

1.1.4. Physical Plan 和 Executor

优化后的逻辑计划会用一棵树表示

Optimized Logical Plan

对优化后的逻辑计划进行拆分, 形成一颗颗子树, 成为 Plan Fragment, 布置在分布式的节点中

image.png

  • Plan Fragment :
    • 目标: 最小化网络数据传输
    • 根据数据的分布来布置不同的子树(数据亲和性
    • 不同Fragment之间通过Shuffle算子交互
  • Executor
    • 单机:cache,pipeline,SIMD
    • 多机:一个fragment多个实例

2. 常见查询优化器

2.1. RBO(Rule-based Optimizer)

目标: 使进行join操作的两个表行和列尽可能小

2.1.1. 列裁剪

根据select最终展示的列和表间join时需要使用的列, 去除与查询无关的列

image.png

2.1.2. 谓词下推

在join之前进行行的筛选, 减少参与join的表的行

image.png

2.1.3. 传递闭包

根据join时候的等价关系, 传递属性上的筛选条件, 使两表的行数同时减少

image.png

2.1.4. Runtime Filter

根绝join的等价关系, 在join前, 对其中的一个属性进行统计(min-max, hash-list, bloom filter), 使用统计结果会另一个表的属性进行过滤

image.png

bloom filter

  1. 首先需要k个hash函数,每个函数可以把key散列成为1个整数
  2. 初始化时,需要一个长度为n比特的数组,每个比特位初始化为0
  3. 某个key加入集合时,用k个hash函数计算出k个散列值,并把数组中对应的比特位置为1
  4. 判断某个key是否在集合时,用k个hash函数计算出k个散列值,并查询数组中对应的比特位,如果所有的比特位都是1,认为在集合中。

优点: 节省空间

缺点: 容易将不在集合中的元素误判为在集合中; 只能添加无法删除

2.1.5 RBO总结

  • 主流RBO实现一般都有几百条基于经验归纳得到的优化规则
  • 优点: 实现简单, 速度快
  • 缺点: 不能保证得到最优的结果

2.2. CBO(Cost-based Optimizer)

2.2.1. CBO概念

  • 通过计算所有算子的代价, 来得到最终的执行代价
  • 通过RBO得到所有可能的优化方案的代价
  • 选择最小代价的方案

算子代价: 运算过程中CUP, 内存, 磁盘I/O, 网络I/O的开销总和; 通常和算子的输入数据的行数和列数有关

2.2.2 CBO统计信息

  • 原始信息
    • 表的行数, 行平均大小
    • 列: min, max, num nulls等
  • 推导信息
    • 选择率(selectivity): 根据过滤条件返回的数据比例
    • 基数(cardinality): 算子要处理的行数

准确的基数, 远比代价模型本身更重要

2.2.3 CBO表信息收集方式

  1. 在DDL中指定统计信息, 更新时插入
  2. 手动执行explain analyze statement, 触发统计信息
  3. select语句动态采样

CBO统计信息推到规则

推导出最终的选择率, 推到规则等同于概率论推到规则

推出出的表的最终选择率乘以表的基础, 可以得出过滤之后的基数.

cardinality(FILTER)=cardinality(A)selectivity(FILTER)cardinality(FILTER) = cardinality(A) \cdot selectivity(FILTER)

image.png

  • 存在问题

    推到规则要求列于列之间使独立的, 并且值使处于均匀分布的, 但是在现实情境下通常是不成立的.

    值分布不均匀情况下可以使用直方图做更精准的推导

2.2.4 CBO执行计划枚举

对于执行过程中的所有可能的选择情况(如,单表索引扫描OR单表全表扫面; Hash Join OR SortMerge Join; 多表之间的连接方式), CBO通常会枚举出所有可能的情况, 然后通过贪心算法动态规划选出最优的执行计划.

3. 社区开源实践

image.png

3.1. Apache Calcite

3.2. Calcite RBO

3.3. Calcite CBO

4. 前沿趋势

  • 引擎架构进化
  • Cloud
  • 湖仓一体
  • DATA + AI
    • AI4DB
      • 自配置
      • 自诊断和自愈合
      • 自优化
    • DB4AI
      • 内嵌人工智能算法
      • 内嵌机器学习框架