百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT技术 > 正文

SQL解析框架 - Calcite

wptr33 2024-11-23 23:30 12 浏览

最通用的SQL解析框架 - Calcite

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


背景


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


这个流程在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,方法截图如下:


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


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函数来做一个类似的实现。

Calcite源码相关名词释义

名称

解释

作用

SqlNode

SqlTree中的Node

在SqlToRelConverter中转化为RelNode

RexNode

表达式

RexLiteral是常量表达式,如”123”;RexCall是函数表达式,如cast(xx as xx)

RelNode

关系表达式(动词)

常在执行计划中看到,如Project,Join,Aggregate

RelSubset

带有同一Trait的RelNode集合


RelSet

RelSubset集合


RelTrait

特征

RelNode对应的特征,如RelCollation可能是Project中的排序特征

TraitDef

特征定义

定义了Trait对应的一些方法

Convention

转化特征

用于转化RelNode,常见的有SparkConvention,FlinkConvention

Literal

常量


Planner

SQL计划

可用于解析、优化、执行

Program

程序

可根据Rules自行构建,作用和Planner类似

相关文档

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

相关推荐

【推荐】一款开源免费、美观实用的后台管理系统模版

如果您对源码&技术感兴趣,请点赞+收藏+转发+关注,大家的支持是我分享最大的动力!!!项目介绍...

Android架构组件-App架构指南,你还不收藏嘛

本指南适用于那些已经拥有开发Android应用基础知识的开发人员,现在想了解能够开发出更加健壮、优质的应用程序架构。首先需要说明的是:AndroidArchitectureComponents翻...

高德地图经纬度坐标批量拾取(高德地图批量查询经纬度)

使用方法在桌面上新建一个index.txt文件,把下面的代码复制进去保存,再把文件名改成index.html保存,双击运行打开即可...

flutter系列之:UI layout简介(flutter ui设计)

简介对于一个前端框架来说,除了各个组件之外,最重要的就是将这些组件进行连接的布局了。布局的英文名叫做layout,就是用来描述如何将组件进行摆放的一个约束。...

Android开发基础入门(一):UI与基础控件

Android基础入门前言:...

iOS的布局体系-流式布局MyFlowLayout

iOS布局体系的概览在我的CSDN博客中的几篇文章分别介绍MyLayout布局体系中的视图从一个方向依次排列的线性布局(MyLinearLayout)、视图层叠且停靠于父布局视图某个位置的框架布局(M...

TDesign企业级开源设计系统越发成熟稳定,支持 Vue3 / 小程序

TDesing发展越来越好了,出了好几套组件库,很成熟稳定了,新项目完全可以考虑使用。...

WinForm实现窗体自适应缩放(winform窗口缩放)

众所周知,...

winform项目——仿QQ即时通讯程序03:搭建登录界面

上两篇文章已经对CIM仿QQ即时通讯项目进行了需求分析和数据库设计。winform项目——仿QQ即时通讯程序01:原理及项目分析...

App自动化测试|原生app元素定位方法

元素定位方法介绍及应用Appium方法定位原生app元素...

61.C# TableLayoutPanel控件(c# tabcontrol)

摘要TableLayoutPanel在网格中排列内容,提供类似于HTML元素的功能。TableLayoutPanel控件允许你将控件放在网格布局中,而无需精确指定每个控件的位置。其单元格...

想要深入学习Android性能优化?看完这篇直接让你一步到位

...

12个python数据处理常用内置函数(python 的内置函数)

在python数据分析中,经常需要对字符串进行各种处理,例如拼接字符串、检索字符串等。下面我将对python中常用的内置字符串操作函数进行介绍。1.计算字符串的长度-len()函数str1='我爱py...

如何用Python程序将几十个PDF文件合并成一个PDF?其实只要这四步

假定你有一个很无聊的任务,需要将几十个PDF文件合并成一个PDF文件。每一个文件都有一个封面作为第一页,但你不希望合并后的文件中重复出现这些封面。即使有许多免费的程序可以合并PDF,很多也只是简单的将...

Python入门知识点总结,Python三大数据类型、数据结构、控制流

Python基础的重要性不言而喻,是每一个入门Python学习者所必备的知识点,作为Python入门,这部分知识点显得很庞杂,内容分支很多,大部分同学在刚刚学习时一头雾水。...