一个典型的 SQL 请求的流程如下图所示:
Parser
词法/语法解析模块
Parser 是整个 SQL 执行引擎的词法/语法解析器,在收到用户发送的 SQL 请求串后,Parser 会将字符串分成一个个的“单词”,并根据预先设定好的语法规则解析整个请求,将 SQL 请求字符串转换成带有语法结构信息的内存数据结构,我们称为“语法树”(Syntax Tree)。
为了加速 SQL 请求的处理速度,OceanBase 数据库对 SQL 请求采用了特有的“快速参数化”,以加速查找 plan cache 的速度。
Plan Ca**che**
执行**计划缓存模块**
执行计划的生成是一个比较复杂的过程,耗时比较长,尤其是在 OLTP 场景中,这个耗时往往不可忽略。为了加速 SQL 请求的处理过程,SQL 执行引擎会将该 SQL 第一次生成的执行计划缓存在内存中,后续的执行可以反复执行这个计划,避免了重复查询优化的过程。
Resolver
语义解析模块
当 SQL 请求字符串经过语法、词法解析,生成“语法树”之后,Resolver 会进一步将该语法树转换为带有数据库语义信息的内部数据结构。在这一过程中,Resolver 将根据数据库元信息将 SQL 请求中的 token 翻译成对应的对象(例如库、表、列、索引等),生成的数据结构叫做 Statement Tree。
Transfomer
逻辑改写模块
在查询优化中,经常利用等价改写的方式,将用户 SQL 转换为与之等价的另一条 SQL,以便于优化器为之生成最佳的执行计划,我们称这一过程为“查询改写”。Transformer 在 Resolver 之后,分析用户 SQL 的语义,并根据内部的规则或代价模型,将用户 SQL“改写”为与之等价的其他形式,并将其提供给后续的优化器做进一步的优化。Transformer 的工作方式是在原 Statement Tree 上做等价变换,变换的结果仍然是一棵 Statement Tree。
Optimizer 优化器
优化器是整个 SQL 请求优化的核心,其作用是为 SQL 请求生成最佳的执行计划。在优化过程中,优化器需要综合考虑 SQL 请求的语义、对象数据特征、对象物理分布等多方面因素,解决访问路径选择、连接顺序选择、连接算法选择、分布式计划生成等多个核心问题,最终选择一个对应该 SQL 的最佳执行计划。SQL 的执行计划是一棵由多个操作符构成的执行树,每一个操作符提供 open(), next(), close() 的调用接口,在执行时,通过层层的调用,将用户需要的执行返回。
Code Generator 代码生成器
优化器负责生成最佳的执行计划,但其输出的结果并不能立即执行,还需要通过代码生成器将其转换为可执行的代码,这个过程由 Code Generator 负责。需要指出的是,Code Generator 执行的过程只是将优化器的生成结果翻译成可执行代码,并不做任何优化选择。
Executor
执行器
当 SQL 的执行计划生成后,Executor 会启动该 SQL 的执行过程。对于不同类型的执行计划,Executor 的逻辑有很大的不同:
对于本地执行计划,Executor 会简单的从执行计划的顶端的算子开始调用,由算子自身的逻辑完成整个执行的过程,并返回执行结果;
对于远程或分布式计划,Executor 需要根据预选的划分,将执行树分成多个可以调度的 job,并通过 RPC 将其发送给相关的节点执行,具体的执行过程可以参考 分布式执行和并行查询 章节。