sql (Structured Query Language: 结构化查询语言) 是高级的费过程化编程语言,允许用户在高层数据结构上工作,是一种数据查询和程序设计语言,也是 (ANSI) 的一项标准的计算机语言. but... 目前仍然存在着许多不同版本的 sql 语言,为了与 ANSI 标准相兼容,它们必须以相似的方式共同地来支持一些主要的命令 (比如 SELECT、UPDATE、DELETE、INSERT、WHERE 等等).
在标准 SQL 中,SQL 语句包含四种类型
DML(Data Manipulation Language):数据操作语言,用来定义数据库记录(数据)。
DCL(Data Control Language):数据控制语言,用来定义访问权限和安全级别。
DQL(Data Query Language):数据查询语言,用来查询记录(数据)。
DDL(Data Definition Language):数据定义语言,用来定义数据库对象(库,表,列等)
2.1 MySQL
以 mysql 为例,sql 执行流程大致分为以下节点 (mysql server 层代码,不包含引擎层事务 /log 等操作):
mysqlLex: mysql 自身的词法分析程序,C++ 语言开发,基于输入的语句进行分词,并解析除每个分词的意义。分词的本质便是正则表达式的匹配过程。源码在 sql/sql_lex.cc
Bision: 根据 mysql 定义的语法规则,进行语法解析,语法解析就是生成语法树的过程。核心是如何涉及合适的存储结构以及相关算法,去存储和遍历所有的信息
语法解析中,生成语法树:
mysql 分析器: SQL 解析,针对关键词 / 非关键词进行提取、解析,并生成解析语法树。如果分析到语法错误,会抛出异常: ERROR: You have an error in your SQL syntax. 同时该阶段也会做一些校验,如不存在字段会抛出异常: unknow column in field list.
引申点:
a. 语法树生成规则
b. mysql 的优化规则
2.2 hive sql
Hive 是基于 Hadoop 构建的一套数据仓库分析系统,它提供了丰富的 SQL 查询方式来分析存储在 Hadoop 分布式文件系统中的数据,可以将结构化的数据文件映射为一张数据库表,并提供完整的 SQL 查询功能,可以将 SQL 语句转换为 MapReduce 任务进行运行,通过自己的 SQL 去查询分析需要的内容,这套 SQL 简称 Hive SQL,使不熟悉 mapreduce 的用户很方便的利用 SQL 语言查询,汇总,分析数据
hive 架构图:
Driver:
输入了 sql 字符串,对 sql 字符串进行解析,转化程抽象语法树,再转化成逻辑计划,然后使用优化工具对逻辑计划进行优化,最终生成物理计划(序列化反序列化,UDF 函数),交给 Execution 执行引擎,提交到 MapReduce 上执行(输入和输出可以是本地的也可以是 HDFS/Hbase)见下图的 hive 架构
hiveSql 的执行流程如下:
sql 写出来以后只是一些字符串的拼接,所以要经过一系列的解析处理,才能最终变成集群上的执行的作业
(1)Parser:将 sql 解析为 AST(抽象语法树),会进行语法校验,AST 本质还是字符串
(2)Analyzer:语法解析,生成 QB(query block)
(3)Logicl Plan:逻辑执行计划解析,生成一堆 Opertator Tree
(4)Logical optimizer: 进行逻辑执行计划优化,生成一堆优化后的 Opertator Tree
(5)Phsical plan:物理执行计划解析,生成 tasktree
(6)Phsical Optimizer:进行物理执行计划优化,生成优化后的 tasktree,该任务即是集群上的执行的作业
结论:经过以上的六步,普通的字符串 sql 被解析映射成了集群上的执行任务,最重要的两步是 逻辑执行计划优化和物理执行计划优化(图中红线圈画)
Antlr: Antrl 是一种语言识别的工具,基于 JAVA 开发,可以用来构造领域语言。它提供了一个框架,可以通过包含 java, C++, 或 C# 动作 (action) 的语法描述来构造语言识别器,编译器和解释器.Antlr 完成了 hive 词法分析、语法分析、语义分析、中间代码生成的过程.
AST 语法树举例:
引申学习:
a. 从 hivesql 的执行机制可以看出,hive 并不适合用于联机事务处理,无法提供实时查询功能;最适合应用在基于大量不可变数据的批处理作业
b. Antlr 的解析流程
c. hive 的优化规则
2.3 flink sql
Flink SQL 是 Flink 中最高级的抽象,可以划分为 SQL --> Table API --> DataStream/DataSetAPI --> Stateful Stream Processing
Flink SQL 包含 DML 数据操作语言、 DDL 数据语言, DQL 数据查询语言,不包含 DCL 语言。
(1)首先,FlinkSQL 底层使用的是 Apache Calcite 引擎来处理 SQL 语句,Calcite 会使用 javaCC 做 SQL 解析,javaCC 根据 Calcite 中定义的 Parser.jj 文件,生成一系列的 java 代码,生成的 java 代码会把 SQL 转换成 AST 抽象语法树(即 SQLNode 类型)。
(2)生成的 SqlNode 抽象语法树,他是一个未经验证的抽象语法树,这时 SQL Validator 会获取 Flink Catalog 中的元数据信息来验证 sql 语法,元数据信息检查包括表名,字段名,函数名,数据类型等检查。然后生成一个校验后的 SqlNode。
(3)到达这步后,只是将 SQL 解析到 java 数据结构的固定节点上,并没有给出相关节点之间的关联关系以及每个节点的类型信息。
所以,还需要将 SqlNode 转换为逻辑计划,也就是 LogicalPlan,在转换过程中,会使用 SqlToOperationConverter 类,来将 SqlNode 转换为 Operation,Operation 会根据 SQL 语法来执行创建表或者删除表等操作,同时 FlinkPlannerImpl.rel () 方法会将 SQLNode 转换成 RelNode 树,并返回 RelRoot。
(4)第 4 步将执行 Optimize 操作,按照预定义的优化规则 RelOptRule 优化逻辑计划。
Calcite 中的优化器 RelOptPlanner 有两种,一是基于规则优化(RBO)的 HepPlanner,二是基于代价优化(CBO)的 VolcanoPlanner。然后得到优化后的 RelNode, 再基于 Flink 里面的 rules 将优化后的逻辑计划转换成物理计划。
(5)第 5 步 执行 execute 操作,会通过代码生成 transformation,然后递归遍历各节点,将 DataStreamRelNode 转换成 DataStream,在这期间,会依次递归调用 DataStreamUnion、DataStreamCalc、DataStreamScan 类中重写的 translateToPlan 方法。递归调用各节点的 translateToPlan,实际是利用 CodeGen 元编成 Flink 的各种算子,相当于直接利用 Flink 的 DataSet 或者 DataStream 开发程序。
(6)最后进一步编译成可执行的 JobGraph 提交运行。
Flink SQL 使用 Apache Calcite 作为解析器和优化器
Calcite : 一种动态数据管理框架,它具备很多典型数据库管理系统的功能 如 SQL 解析、 SQL 校验、 SQL 查询优化、 SQL 生成以及数据连接查询等,但是又省略了一些关键的功能,如 Calcite 并不存储相关的元数据和基本数据,不完全包含相关处理数据的算法等。
引申学习:
a. flink sql 优化规则
持续补充 ing...
在实际工作过程中会涉及到相关的 sql 优化,比如将非研发的业务老师写的复杂嵌套 sql 后台自动改为非嵌套执行,提高查询性能。支持 redisSQL, 以标准 SQL 格式解析成后台可执行的 redis 命令。目前采用的开源 jsqlparser 框架来实现语法树的解析,好处是操作简单,只对 sql 语句进行拆分,解析成 java 类的层次结构,支持 visitor 模式,与数据库无关。缺点是只支持常见的 SQL 语法集,如若要扩展语法需改其源码,对代码的侵入性与维护性造成影响。想要做好 sql 解析优化相关的工作,还是要深入了解 sql 的执行原理,了解各个 sql 引擎的特点与优劣。站在架构的角度来思考来思考问题.
工欲善其事,必先利其器.
作者:京东科技 李丹枫
来源:京东云开发者社区 转载请注明来源