执行

上一篇讲述了如何通过scala提供的内置DSL支持,实现一个可以解析sql的解析器,这篇讲如何拿到了解析结果-AST以后,如何在数据上进行操作,得到我们想要的结果。之前说到,为什么选择scala作为这个引擎的实现,之一是scala提供了方便的DSL实现支持,其二是因为作为一门函数式编程语言,scala提供了丰富对于集合操作的函数。此外,函数在scala中是一个独立的类型,所以能够把现有的函数进行组合,得到更为强大的函数(和上一篇提到的用解析组合子组合已有的解析器得到更强大的解析器一样)。

首先,我们需要弄清楚普通sql语句的执行顺序,一般来说,sql的书写顺序为

  • SELECT[DISTINCT]
  • FROM
  • WHERE
  • GROUP BY
  • HAVING
  • UNION
  • ORDER BY

但是,执行顺序为

  • FROM
  • WHERE
  • GROUP BY
  • HAVING
  • SELECT
  • DISTINCT
  • UNION
  • ORDER BY

本次实现的sql执行不支持join,所以省去了union部分,但是大致顺序差不多,如果把一个List<Map>想象成一个数据库的表,那么执行顺序可以用下图所示,图中标绿色的箭头表示可以并发执行,聚合函数的执行是不能并发的,但是因为已经把数据给分组了,故可以在更高的一个层次并发。

了解了大致的执行流程,下面说一下各个流程执行所用到的函数。

  • where子句
    where子句的执行,利用了 filter函数,将不符合条件的数据给过滤掉。举个例子,下面这个段代码,将列表中的奇数给过滤掉。

    scala> val L = List(1,2,3,4,5,6)
    L: List[Int] = List(1, 2, 3, 4, 5, 6)
    scala> L filter(_%2==0)
    res2: List[Int] = List(2, 4, 6)

    对每个元素进行判断这个步骤其实是可以并发执行的,你只需要这样写,就能进行安全的并发操作。

    scala> L.par.filter(_%2==0).toList
    res4: List[Int] = List(2, 4, 6)

    在scala_sql引擎中,实现where的函数为

    def where(where: Option[SqlExpr]): Table = {
    where match {
    case None => table
    case Some(x: SqlExpr) => table filter (evalWhereEachRow(_, x))
    }
    }

    其中evalWhereEachRow(_,x)是另外一个函数,第一个参数是table中的一列,即一个Map对象,第二个参数是由sql解析得到的AST中,对应where子句的部分。

  • groupBy子句
    scala中也提供了对于集合的groupBy操作,接着上个例子
    scala> L groupBy(_%2)
    res6: scala.collection.immutable.Map[Int,List[Int]] = Map(1 -> List(1, 3, 5), 0 -> List(2, 4, 6))

    上面这个函数,把L这个list根据奇偶分组。
    在scala _sql引擎中,实现groupBy的函数为

     def evalGroupBy(table: Table, groupby: SqlGroupBy): Seq[Table] = {
    val keys: Seq[String] = groupby.keys map {
    case x: FieldIdent => x.name
    }
    table.groupBy(row => keys.map(row(_))).map(_._2).toSeq
    }

结论

DSL主要有两种,内部DSL和外部DSL,对于外部DSL,需要一个解析器来解析DSL的脚本,得到能够让程序处理的数据结构,这种数据结构通常是一种AST。实现需要的解析器,大体有两种方式:

  • 手工写一个,例如druid中的sql解析模块。
  • 利用ANTRL等解析生成器,通过编写语法规则,生成一个解析器。

近年来随着函数式编程慢慢得到工业界的关注,利用parser combinator(解析组合子)的方式来编写解析器实现DSL也进入了大众视野。

用scala实现一个sql执行引擎-(下)的更多相关文章

  1. 用scala实现一个sql执行引擎-(上)

    前言 在实时计算中,通常是从队列中收集原始数据,这种原始数据在内存中通常是一个java bean,把数据收集过来以后,通常会把数据落地到数据库,供后面的ETL使用.举个一个简单的例子,对一个游戏来说, ...

  2. 自己实现一个SQL解析引擎

    自己实现一个SQL解析引擎 功能:将用户输入的SQL语句序列转换为一个可运行的操作序列,并返回查询的结果集. SQL的解析引擎包含查询编译与查询优化和查询的执行,主要包含3个步骤: 查询分析: 制定逻 ...

  3. 自己动手写SQL执行引擎

    自己动手写SQL执行引擎 前言 在阅读了大量关于数据库的资料后,笔者情不自禁产生了一个造数据库轮子的想法.来验证一下自己对于数据库底层原理的掌握是否牢靠.在笔者的github中给这个database起 ...

  4. 给隔壁的妹子讲『一个SQL语句是如何执行的?』

    前言 SQL作为Web开发是永远离开不的一个话题,天天写SQL,可是你知道一个SQL是如何执行的吗? select name from user where id = 1; 上面是一个简单的查询语句, ...

  5. Oracle数据库该如何着手优化一个SQL

    这是个终极问题,因为优化本身的复杂性实在是难以总结的,很多时候优化的方法并不是用到了什么高深莫测的技术,而只是一个思想意识层面的差异,而这些都很可能连带导致性能表现上的巨大差异. 所以有时候我们应该先 ...

  6. SQL执行过程中的性能负载点

    一.SQL执行过程 1.用户连接数据库,执行SQL语句: 2.先在内存进行内存读,找到了所需数据就直接交给用户工作空间: 3.内存读失败,也就说在内存中没找到支持SQL所需数据,就进行物理读,也就是到 ...

  7. spark sql 执行计划生成案例

    前言 一个SQL从词法解析.语法解析.逻辑执行计划.物理执行计划最终转换为可以执行的RDD,中间经历了很多的步骤和流程.其中词法分析和语法分析均有ANTLR4完成,可以进一步学习ANTLR4的相关知识 ...

  8. hint不当索引,影响多表连接方式,最终导致SQL执行缓慢

    需求:一个SQL执行特别慢,无法返回结果,需要进行优化,最终返回结果即可. 一.SQL分析 二.尝试执行,观测执行计划 三.修改SQL 四.问题总结 一.SQL分析 )SQL文本,执行时间,执行用户 ...

  9. spring 默认情况下事务是惟一的 同一个方法里面第一个sql开启后 在执行完 将事务传递给下一个sql

    spring 默认情况下事务是惟一的 同一个方法里面第一个sql开启后 在执行完 将事务传递给下一个sql

随机推荐

  1. bootloader制作过程

    主机环境:Ubuntu10.04.4 LTS 使用工具:buildroot-201208 目  标  板:S3C2410 --------------------------------------- ...

  2. hbase运行shell时ERROR:org.apache.hadoop.hbase.PleaseHoldException: Master is initializing 的解决办法

    这个问题困扰了我一天多的时间,百度搜索的前几条的答案也是很扯淡的,说什么把/etc/hosts文件下的127.0.1.1改成127.0.0.1就行了,我也只能呵呵了.今天早上起得很晚,中午迪哥请我们去 ...

  3. 潜入ICU的四逆汤

    制附子50克(先煎2小时).干姜15克.炙甘草10克.桂枝10克.上好肉桂10克(后下).煎取药液300毫升,分三次鼻饲.这是昨天我给A先生病危的父亲开的处方:四逆汤加肉桂.桂枝. 昨天上午的门诊到2 ...

  4. React 附件动画API ReactCSSTransitionGroup

    React为动画提供了一个附加组件ReactTransitionGroup,这个附加组件是动画的底层API,并且还提供了一个附件组件ReactCSSTransitionGroup,ReactCSSTr ...

  5. JavaScript笔记基础篇(二)

    基础篇主要是总结一些工作中遇到的技术问题是如何解决的,应为本人属于刚入行阶段技术并非大神如果笔记中有哪些错误,或者自己的一些想法希望大家多多交流互相学习. 1.ToFixed()函数 今天在做Birt ...

  6. 2016-08-05:samba服务器配置

    centos samba服务器配置 配置smb.conf文件 [share] path = /home/lee writable = yes 添加smb用户 smbpasswd -a root 启动s ...

  7. JavaWeb项目连接Oracle数据库

    参考网址:http://jingyan.baidu.com/article/0320e2c1d4dd0b1b87507b38.html 既然你要链接oracle数据库 ,那么首先就是先打开我们的ora ...

  8. VBS 相关知识 笔记

    1.Option Explicit: 必须声明了变量之后才能赋值.  原话:语句在模块级别中使用,强制显式声明模块中的所有变量. w3scholl看到的内容: 变量声明 您可以使用 Dim.Publi ...

  9. IRelationalOperator空间关系接口简介

    几何对象之间都存在某种关联关系,如包含,相等,在内部,相交,叠加等.这些关联关系的获得都可以通过IRelationalOperator接口来获得,关系运算是在两个几何对象间进行的,通过IRelatio ...

  10. C++ #include .h extern 的相关关系及说明

    函数和变量都有声明和定义两个写法.声明的目的是告诉别的代码这个变量的名称,而定义比声明多了一个功能,除了告知名称以外,还会为这个变量分配内存.对于函数来说,加不加extern都没有关系,因为有函数体一 ...