目录
一、概述
原文大佬的这篇查询源码解析写的很全面,主要是从一个sql语句出发,从使用层面和源码层面解析sql的底层执行过程。这里摘抄下来为后续的Doris慢查询分析做好技术储备。
在Doris引擎中,FE根据用户的查询生成一个完整的逻辑规划,然后基于这个逻辑规划生成一个分布式的逻辑规划,当FE生成好查询计划树后,BE对应的各种Plan Node(Scan,Join,Union,Aggregation, Sort等)执行自己负责的操作即可。
整个查询过程可以分为3个模块:
- 查询优化器:将sql文本转换成一个“最佳的”分布式物理执行计划(FE生成查询计划)
- 查询调度器:将执行计划调度到计算节点(FE分发分配PlanFragment)
- 查询执行器:计算节点执行具体的物理执行计划(BE执行查询)
接下来依次介绍这三个模块的执行流程及原理。
二、查询规划器
一条sql进入Doris后,有多种可以执行的方式。查询规划器的目的是为了生成一个BE能够识别的 “最佳的” 分布式物理执行计划,主要分为两个步骤:SQL --> PlanNodeTree 和PlanNodeTree -->PlanFragmentTree。
相关概念:
- PlanNode: 逻辑算子
- PlanNodeTree :逻辑查询计划
- PlanFragmentTree:分布式查询计划
- Plan Fragment:Plan NodeTree的子树 + Data Sink节点
完整的流程图如下:

2.1 生成单节点查询计划
即SQL --> PlanNodeTree的过程,其中Plan Node代表逻辑算子。该步骤包括Plan Tree的生成,谓词下推,Table Partitions pruning,Column projections,Cost-based优化等。


2.2 单节点的查询计划分布式化
将单节点的查询计划分布式化,即PlanNodeTree --->PlanFragmentTree,其中FragmentTree是BE执行查询的最小单位,至少包含一个算子。分布式化的目标是最小化数据移动和最大化本地Scan,分布式的方法是增加ExchangeNode以及DataSink,执行计划树会以ExchangeNode为边界拆分为PlanFragment。
分布式查询计划是由多个Plan Fragment 组成的,例如:Plan Fragment 0,Plan Fragment 1,Plan Fragment 2等。每个 Fragment 负责查询计划的一部分,各个Fragment之间会通过 DataStreamSink和ExchangeNode 算子进行数据的传输。



- 拆分PlanNodeTree
分布式查询计划是由多个Plan Fragment 组成的,例如:Plan Fragment 0,Plan Fragment 1,Plan Fragment 2等

-
数据传输
各个Fragment之间会通过 DataStreamSink和ExchangeNode 算子进行数据的传输。

完整的流程图如下:

查询优化器在运行过程中,又可以细分成很多个执行阶段:
- 词法语法解析
- 语义解析
- query改写
- 单机执行计划
- 分布式执行计划
2.2.1 词法语法解析
-
首先会进入词法解析,会将一个SQL中的关键词解析出来,如:select、from、join、group by等(如下图的蓝色部分)。
-
然后会进入语法解析,该阶段会判断语法是否正确
经过词法语法解析后,最终一条sql语句被转成抽象语法树(AST Tree)
2.2.2 语义解析
语义解析的目的是为了保证查询的列名和表名是正确的,包括如下部分:
-
元数据的识别和解析(Binder):检查表权限,列是否存在类型是否支持等,然后解析(Binder)出来
-
SQL合法性检查
-
SQL重写:如select * 重写为 select col1,col2...
-
函数检查
-
别名处理
2.2.3 query改写
该阶段会按照指定的规则给之前生成的抽象语法树(AST Tree)做一些变化。query改写又分为表达式改写和子查询解嵌套
2.2.4 单机执行计划
经过前3步的处理,Doris对于一些基于规则的转换已经做完了,这时候SQL在内核中还是一颗抽象语法树(AST Tree)。此时Doris需要将抽象语法树转换成一个单机的执行规划。 比如会将下图中的SQL转成一个逻辑计划树PlanNodeTree,在转换期间会做一些优化,如 Join Reorder以及谓词下推。

-
Join Reorder
上图中的sql语句如果不做优化,会按照默认的顺序进行join,即t1跟t2先进行关联,会产生一个笛卡尔积(因为t1和t2没有关联条件),这很有可能导致OOM。因此,Doris会通过Join Reorder对这个join重新排序,使得中间join的结果集变小,这样t1与t2产生的笛卡尔积也就消失了。

本文从使用和源码层面解析Doris引擎中SQL的底层执行过程。整个查询分为查询优化器、调度器和执行器三个模块。详细介绍了查询规划器生成分布式物理执行计划的步骤,查询调度器的流程及源码,以及查询执行器的数据交互和结果展示等内容。
最低0.47元/天 解锁文章
755

被折叠的 条评论
为什么被折叠?



