"select * from tb_user where userid > 10;"这是再简单不过的一条sql语句,从表tb_user中筛选出userid大于10的所有记录。我们平时会写各种各样或简单或复杂的sql语句,然后不一会儿就会得到我们想要的结果集。但是你有没有想过从一条sql到一个结果集,这中间经历了多少坎坷呢?

SQL引擎

小到传统的单机数据库,大到分布式数据库、大数据计算引擎,他们大都可以借助SQL引擎完成“接受一条sql语句然后返回查询结果”的功能。单机数据库可能处理的数据量有限,而大数据计算引擎补充了对海量数据的查询能力。但是他们核心的执行逻辑都是一样的,大致可以通过下面的流程来概括:

我们本次要讨论的就是前两个模块:词法分析和语法分析形成抽象语法树(AST)的内容。

抽象语法树

上面说到了sql引擎的一般执行流程,一条sql语句首先会经过词法分析进行“分词”操作,然后利用语法解析器进行语法分析并形成一棵抽象语法树。这棵抽象语法树其实就简单的可以理解为逻辑执行计划了,他会经过查询优化器利用一些规则进行逻辑计划的优化,得到一棵优化后的逻辑计划树,我们所熟知的“谓词下推”、“剪枝”等操作其实就是在这个过程中实现的。得到逻辑计划后,会进一步转换成能够真正进行执行的物理计划,例如怎么扫描数据,怎么聚合各个节点的数据等。最后就是按照物理计划来一步一步的执行了。

简单的描述了一下SQL引擎等执行流程,我们来着重分析一下前两个阶段吧:词法分析->语法分析->AST

很多的SQL引擎都是借助ANTLR工具来协助进行语法解析,查询引擎presto就是用的antlr做底层sql语法解析的,我们只需要定义好一个语法文件(一般以.g4后缀结束),就可以利用ANTLR工具来进行词法语法解析代码的生成了。

简单示例

先举个简单的小例子:

首先定义一个简单的语法文件:Hello.g4

这个文件中,grammar Hello中的Hello就是一个语法文件,跟我们的Hello.g4的Hello是同一个名字。

在这里面,通过小写来定义规则,例如这里我其实定义了两个规则,一个是检测以“Hello”或者“hello”开头,紧跟一个由小写字母构成的词的规则“r“,另一个是匹配‘i love you'或者‘you love me’的短语的规则“love”。如果你用的是Intellij IDEA并且由ANLTR插件的话,通过右键然后选择Configure ANLTR就会生成词法语法解析的对应类(如下图),其中核心的几个类有HelloLexer、HelloParser、HelloVisitor和HelloListener。

其中,这几个重要的类的作用如下:

HelloLexer:词法解析,可以理解为将sql分割为token;

HelloParser:语法解析,将词法解析的结果进行语法解析,从而形成一棵抽象语法树(AST);

HelloVisitor和HelloListener:进行抽象语法树的遍历,一般都会提供这两种模式,Visitor访问者模式和Listener监听器模式。如果想自己定义遍历的逻辑,可以继承这两个接口,实现对应的方法。

有了这几个类的保证,我们其实就可以简单使用一下我们定义好的规则了。

我们来看一段简单的代码:

这段代码就是使用我们的两个规则的实例:

对于读入的sql表达式先通过Lexer进行词法分析形成tokens,然后通过Parser创建parser对象,对parser对象应用我们的语法规则“r”或“love”后生成对应的抽象语法树。

例如我们先只应用规则“r“,也就是匹配”Hello/hello ***“,我们可以看到输入i love you会在应用规则的时候被检测出不匹配,而输入hello world则可以通过,从而形成一棵AST。

我们看到我们可以通过对AST应用Visit方法来进行遍历,上面展示的是最原始最简单的语法树遍历,只有两个节点,分别是hello和world的内容。

SQL引擎

有了上面的基础,我们就可以看一下SQL引擎是怎样实现的,其实跟上面的例子流程几乎一样,只是每个环节的内容都多了点而已,我们以Presto引擎的词法语法解析来看:

很显然,它也是需要有一个SqlBase.g4语法文件,然后里面会定义一些规则、变量等;

他也会生成这么几个重要的类:

然后它的调用也是如出一辙:

然后对生成的AST进行遍历

再往下就是各种visit的实现了,由于sql语法树节点类型众多,因此会有很多不同的visit实现,下面展示的也只是其中的一部分,每个visit方法会对sql语句中涉及到该部分的模块单独拿来进行遍历、分析。

例如下面这段,就是对于join算子的遍历解析,上来会先判断Join的类型是否是自然连接,如果是自然连接则直接抛出”不支持自然连接“的异常。

当一条sql语句的AST被遍历了个遍之后,该条语句的信息其实也已经被引擎掌握了,就会生成对应的逻辑计划,然后再进一步生成物理计划,最后真正的被引擎执行。

总结

以上就是一条sql语句进行sql引擎后进行词法语法解析形成AST的过程,其实无论是开始讲的简单例子也好,后面分析的Presto引擎也好,他们都是相同的道理。至于.g4中的语法规则,目前Presto支持ANSI SQL的词法和语义支持,不同的SQL引擎可能会支持不同的标准,例如Hive SQL是一种类SQL的查询表达,如果体现在这里的话,可能就是.g4文件的规则内容会有所不同了~~

☞腾讯宣布捐赠1亿元驰援河南;苹果回应iPhone 安全隐患;贝索斯完成10分钟太空之旅|极客头条☞区块链生态系统将崩溃、Rust 超越 Go、无服务器成主导,这十大计算机预测将成真?☞“我想再当一次 CEO,所以我离开了 IBM”

SQL 引擎如何把语句转换为一个抽象语法树?相关推荐

  1. jsqlparser:基于抽象语法树(AST)遍历SQL语句的语法元素

    jsqlparser是一个java的SQL语句解析器,基于它可以实现很多之前无法完成的工作. <!-- maven 依赖库引用 --><dependency><group ...

  2. 【编译原理】构建一个简单的解释器(Let’s Build A Simple Interpreter. Part 7.)(笔记)解释器 interpreter 解析器 parser 抽象语法树AST

    [编译原理]让我们来构建一个简单的解释器(Let's Build A Simple Interpreter. Part 7.) 文章目录 python代码 插--后序遍历 C语言代码(有错误) C语言 ...

  3. 抽象语法树 Abstract syntax tree

    什么是抽象语法树? 在计算机科学中,抽象语法和抽象语法树其实是源代码的抽象语法结构的树状表现形式 在线编辑器 我们常用的浏览器就是通过将js代码转化为抽象语法树来进行下一步的分析等其他操作.所以将js ...

  4. python 抽象语法树_抽象语法树(Abstract Syntax Tree)

    一般来说,程序中的一段源代码在执行之前会经历下面三个步骤 1 分词/词法分析 这个过程会将由字符组成的字符串分解成有意义的代码快,这些代码块被称为词法单元.例如 var a = 4:会被分解成 var ...

  5. 从零写一个编译器(九):语义分析之构造抽象语法树(AST)

    项目的完整代码在 C2j-Compiler 前言 在上一篇完成了符号表的构建,下一步就是输出抽象语法树(Abstract Syntax Tree,AST) 抽象语法树(abstract syntax ...

  6. 抽象语法树 c语言,一个简单的例子看懂抽象语法树的魔力

    在计算机科学中,抽象语法树(Abstract Syntax Tree,AST),或简称语法树(Syntax tree),是源代码语法结构的一种抽象表示.它以树状的形式表现编程语言的语法结构,树上的每个 ...

  7. js 数组 实现 完全树_JavaScript的工作原理:解析、抽象语法树(AST)+ 提升编译速度5个技巧

    摘要: JS的"编译原理". 原文:JavaScript的工作原理:解析.抽象语法树(AST)+ 提升编译速度5个技巧 作者:前端小智 Fundebug经授权转载,版权归原作者所有 ...

  8. JavaScript 是如何工作的:解析、抽象语法树(AST)+ 提升编译速度5个技巧

    这是专门探索 JavaScript 及其所构建的组件的系列文章的第 14 篇. 如果你错过了前面的章节,可以在这里找到它们: JavaScript 是如何工作的:引擎,运行时和调用堆栈的概述! Jav ...

  9. js最小化浏览器_「译」解析、抽象语法树(ast) +如何最小化解析时间的5个技巧...

    前言 该系列课程会在本周陆续更新完毕,主要讲解的都是工作中可能会遇到的真实开发中比较重要的问题以及相应的解决方法.通过本系列的课程学习,希望能对你日常的工作带来些许变化.当然,欢迎大家关注我,我将持续 ...

最新文章

  1. LVS负载均衡之持久性连接介绍(session篇)
  2. php处理不确定笛卡尔积,PHP笛卡尔积实现算法示例
  3. 【转载】App.config/Web.config 中特殊字符的处理
  4. oracle 在所有表中查某个值,oracle需要查询某个字段的值在其他某个表中有没的值有相同...
  5. 在.Net中使用log4Net
  6. js 生成二维码_js 生成二维码
  7. 两个CRunTime库排序算法调用,但是更值得注意的”指针“以及“三目”
  8. Ambari--服务管理
  9. winform自定义用户控件
  10. Lanczos 法 和 QR分解 求解实对称矩阵特征值
  11. matlab中算术平方根,改进的平方根法matlab
  12. ORA-01045: user lacks CREATE SESSION privilege
  13. 怎么显示文件后缀名?很容易的几个步骤
  14. LINUX如何设置numlock键开机状态
  15. 【深度学习】CNN+Transformer汇总
  16. pythonencoding etf-8_Python 量化分析ETF指数基金投资
  17. Django实现视频播放
  18. pytest合集(5)— Function函数
  19. 命令行quser logoff
  20. 如何给JButton添加图标,并使图标沾满整个按钮。

热门文章

  1. 背包九讲 ----- 01背包问题模版
  2. java对象的浅克隆和深克隆
  3. 一本通1623Sherlock and His Girlfriend
  4. Django Rest Framework源码剖析(七)-----分页
  5. Selenium WebDriver Api 知识梳理
  6. Python 常用命令
  7. Java基础之Maven
  8. [算法][包围盒]AABB简单类
  9. 转载关于通过判断浏览器的userAgent,用正则来判断是否是ios和Android客户端
  10. linux 常用到的命令(centos 6.5)