热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

SQL解析框架Calcite

注:本文转自我的个人博客SQL解析框架–Calcite。最通用的SQL解析框架–Calcite最近在研究Flink,在flink-table中看到了calcite,想到自己一年前刚

注:本文转自我的个人博客 SQL解析框架 – Calcite。

最通用的SQL解析框架 – Calcite

最近在研究Flink,在flink-table中看到了calcite,想到自己一年前刚刚从事大数据时,在Hive SQL就对SQL解析产生了很大的好奇,但当时对于这么多的概念一下子接受不过来就放弃了对calcite的研究,觉得现在还是应该再好好做一个总结。

背景

如果你经常做数据处理一类的工作,必定不会对SQL感到陌生。Calcite作为业内通用的SQL处理器,被广泛的运用在了Hive、Flink、Beam等顶级开源项目中。
过去不少博客中提到的SQL解析部分(如spark-catalyst)往往都是说到这样一个流程:

《SQL解析框架 - Calcite》 SQL解析流程

这个流程在Calcite中也是适用的,继续往下看。

速览

先看一段对SQL执行完整的一套代码。分为四个步骤:

  1. SQL解析
  2. SqlNode转换
  3. 优化
  4. 执行

// Convert query to SqlNode
String sql = "select price from transactions";
Config cOnfig= SqlParser.configBuilder().build();
SqlParser parser = SqlParser.create(sql, config);
SqlNode node = parser.parseQuery();

调用SqlParser将SQL语句生成SQL Tree。这部分是Java CC基于Parser.jj文件模板来实现的,输出为SqlNode的Tree的形式,并没有太多的代码,具体文档可见JavaCC Help。

// Convert SqlNode to RelNode
VolcanoPlanner planner = new VolcanoPlanner();
RexBuilder rexBuilder = createRexBuilder();
RelOptCluster cluster = RelOptCluster.create(planner, rexBuilder);
SqlToRelConverter cOnverter= new SqlToRelConverter(...);
RelRoot root = converter.convertQuery(node, false, true);

SqlToRelConverter将SQL Tree转化为Calcite中的RelNode。虽然两种Node都是类似于Tree的形式,但是表示的含义不同。SqlNode有很多种,既包括MIN、MAX这种表达式型的,也包括SELECT、JOIN这种关系型的,转化过程中,将这两种分离成RelNode关系型和RexNode表达式型。

// Optimize RelNode
RelNode optimized = planner.findBestExp();

基于Rule对RelNode做优化。Calcite中Planner分为两种,rule-based和cost-based,在后面将分析更复杂的cost-based的实现。

// Execute
Interpreter interpreter = new Interpreter(dataContext, optimized);
interpreter.enumerator();

在生成的optimized中,根据不同RelNode的类型执行不同的代码,如TableScan执行扫描Table的代码。

SqlNode转换

SqlToRelConverter中,入口函数为convertQuery

public RelRoot convertQuery(SqlNode query, final boolean needsValidation, final boolean top) {
if (needsValidation) {
query = validator.validate(query);
}
RelNode result = convertQueryRecursive(query, top, null).rel;
....
}

可以看出在convertQueryRecursive采取了遍历的方式来解析query,下面的一系列visit方法将SqlNode直接解析成了RexNode,方法截图如下:

《SQL解析框架 - Calcite》 visit方法描述

以visit(SqlLiteral)为例,根据不同的类型生成了不同的RexNode:

《SQL解析框架 - Calcite》 sqlliteral

RexNode再根据不同的SqlNode.getKind()类型组合成不同的RelNode,例如Select -> Project。

优化

优化部分由Planner的findBestExp()执行,其中的策略分为很多种,使用者可以自定义。在calcite中提供了两种Planner:

  • HepPlanner: 基于Rule对RelNode的Tree不断优化直到优化空间为0。
  • VolcanoPlanner: 基于rule+cost采用随机梯度下降法优化,优化至每次优化空间都很小。

以VolcanoPlanner的优化逻辑为例:

  1. 注册RelNode,若发现符合Rule的RelNode,将新构建的RuleCall加入到ruleQueue中,等待后续过程进行优化。
  2. 进入优化环节,判断是否cost比上一次优化降低10%,是则继续优化,否则退出。
  3. 从ruleQueue中提取ruleCall进行优化。
  4. 重新构造RelRoot,更新cost。
  5. 进入2的循环。
  6. 退出。

其实采用VolcanoPlanner相对比较麻烦,因为要基于不同的存储来实现cost的计算,所以大部分大数据框架都是采取Rule-based的Planner形式。这部分的优化其实相对复杂,涉及到比较多的细节,如随机梯度下降的控制,循环次数的控制,内部RelNode的替换等逻辑,一个章节好像没有办法将这个Planner完全说明白,如果有兴趣的话,可以看看具体的实现VolcanoPlanner。

执行

执行根据不同的Node定义了代码的实现方法,从最底层的RelNode依次执行,采用source接收数据,sink发送数据。在Flink中,也有translate函数来做一个类似的实现。

《SQL解析框架 - Calcite》 Node

Calcite源码相关名词释义

名称解释作用
SqlNodeSqlTree中的Node在SqlToRelConverter中转化为RelNode
RexNode表达式RexLiteral是常量表达式,如”123″;RexCall是函数表达式,如cast(xx as xx)
RelNode关系表达式(动词)常在执行计划中看到,如Project,Join,Aggregate
RelSubset带有同一Trait的RelNode集合
RelSetRelSubset集合
RelTrait特征RelNode对应的特征,如RelCollation可能是Project中的排序特征
TraitDef特征定义定义了Trait对应的一些方法
Convention转化特征用于转化RelNode,常见的有SparkConvention,FlinkConvention
Literal常量
PlannerSQL计划可用于解析、优化、执行
Program程序可根据Rules自行构建,作用和Planner类似

相关文档

  • Drill中Calcite优化器代码分析
  • Deep Dive into Spark SQL’s Catalyst Optimizer
  • 编译原理

《SQL解析框架 - Calcite》 加一Blog


推荐阅读
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • 模板引擎StringTemplate的使用方法和特点
    本文介绍了模板引擎StringTemplate的使用方法和特点,包括强制Model和View的分离、Lazy-Evaluation、Recursive enable等。同时,还介绍了StringTemplate语法中的属性和普通字符的使用方法,并提供了向模板填充属性的示例代码。 ... [详细]
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • JVM 学习总结(三)——对象存活判定算法的两种实现
    本文介绍了垃圾收集器在回收堆内存前确定对象存活的两种算法:引用计数算法和可达性分析算法。引用计数算法通过计数器判定对象是否存活,虽然简单高效,但无法解决循环引用的问题;可达性分析算法通过判断对象是否可达来确定存活对象,是主流的Java虚拟机内存管理算法。 ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • Imtryingtofigureoutawaytogeneratetorrentfilesfromabucket,usingtheAWSSDKforGo.我正 ... [详细]
  • Spring学习(4):Spring管理对象之间的关联关系
    本文是关于Spring学习的第四篇文章,讲述了Spring框架中管理对象之间的关联关系。文章介绍了MessageService类和MessagePrinter类的实现,并解释了它们之间的关联关系。通过学习本文,读者可以了解Spring框架中对象之间的关联关系的概念和实现方式。 ... [详细]
  • Android自定义控件绘图篇之Paint函数大汇总
    本文介绍了Android自定义控件绘图篇中的Paint函数大汇总,包括重置画笔、设置颜色、设置透明度、设置样式、设置宽度、设置抗锯齿等功能。通过学习这些函数,可以更好地掌握Paint的用法。 ... [详细]
  • 本文整理了Java面试中常见的问题及相关概念的解析,包括HashMap中为什么重写equals还要重写hashcode、map的分类和常见情况、final关键字的用法、Synchronized和lock的区别、volatile的介绍、Syncronized锁的作用、构造函数和构造函数重载的概念、方法覆盖和方法重载的区别、反射获取和设置对象私有字段的值的方法、通过反射创建对象的方式以及内部类的详解。 ... [详细]
author-avatar
未来不是梦r
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有