Apache Calcite 一条 SQL 的查询计划生成之旅【上】

作者:沈磊(LakeShen),公众号:雷克分析

背景

Apache Calcite 作为一款开源的动态数据管理框架,由于其模块化、可扩展、以及不和任何计算引擎绑定的特性,目前在开源项目和商业化产品中已得到广泛的应用。不仅Apache Flink、Apache Druid、Apache Hive 等明星开源项目在使用 Calcite,腾讯天穹 Super SQL、阿里 MaxCompute、Dremio 等商业化产品的 SQL Planner 也都基于 Calcite 实现。Apache Calcite 俨然成为了 SQL Planner 层的黄金标准、事实趋势。

随着近些年大数据基础设施的不断发展成熟,SQL 已经无可争议地成为大数据计算引擎的主流语言,但与此同时,大量新兴计算引擎、数据库项目的出现,也产生了大量 SQL 方言,运维一个企业级大数据平台需要处理 SQL 的场景越来越多。学习和了解 Apache Calcite,既能帮助我们快速理解 SQL Planner 的原理机制,又能有助于我们利用 Calcite 快速解决以处理 SQL 为中心的各类日常问题(如实现一个SQL Parser、SQL Gateway、SQL Planner 等)。

我们计划从技术实战、原理讲解、源码分析等角度推出系列文章,来介绍如何利用 Apache Calcite 解决一些常见的具体问题,希望能对数据平台工具研发的同学有一些帮助。本文是系列文章的第一篇,将首先介绍 Apache Calcite 的架构设计,同时以一条 SQL 在 Calcite 中的处理流程为主线,对 SQL 解析、元数据验证、执行计划生成及优化、SQL 方言转换等模块的关键原理进行阐述,让读者对 Apache Calcite 有一个初步印象。关于各模块更深入的原理讲解和源码实战,会在后面的系列文章中分篇进行展开。

目标和收益

本文主要讲解 Apache Calcite 的架构设计以及 Calcite 内部 SQL 优化方式,阅读本文,能够从以下几点帮助到你:

  • 整体了解 Apache Calcite ,包括架构设计和核心模块。
  • 从一条 SQL 处理流程的视角出发,通过对 Calcite SQL 解析、校验、关系代数转换、RBO 和 CBO、物化视图改写和方言转换整体流程的讲解,带你了解一条 SQL 的 Calcite 之旅。
  • 了解 Calcite 物化视图改写的两种方式及各自优缺点。
  • 了解 Calcite 中优化器设计的关键细节,以及如何实现对 SQL 方言的改写。

希望阅读完本篇文章后,你能够对 Calcite 整体使用流程有一个初步的认识,下面我们进入正文。

一、Apache Calcite 架构概述

1.1 Apache Calcite 诞生背景

Apache Calcite 自 2013 年 11 月首次在 Github 上进行代码仓库初始化,距今已有 9 年时间。Apache Calcite 前身其实是 optiq。optiq 最开始则是在 Hive 项目中进行使用,其主要目的是为 Hive 提供基于成本模型的优化器。 2014 年 5 月 optiq 独立出来,成为 Apache 社区的孵化项目,同年 9 月正式更名为 Apache Calcite。Calcite 的作者是 Julian Hyde,他早期还写过 Mondrian OLAP Engine 和 olap4j API,目前他不仅是 Calcite 的 VP,同时也是 Apache Arrow、Apache Drill、Apache Druid、Apache Kylin 等开源项目的 PMC。

Apache Calcite 设计的核心目标:“One planner fits all”,它期望在异构引擎、异构存储之上,提供统一的数据管理能力,同时还提供基于关系代数的优化器,它的内部各个模块都是可扩展的,也正是因为这种设计理念,Apache Calcite 才会被众多其他开源项目所使用。

1.2 Apache Calcite 架构设计

Apache Calcite 整体是按模块化进行设计,各个模块支持可扩展,比如 SQL 语法文件、元数据、Transformation Rule(逻辑转换规则)和 Implementation Rule(物理转换规则)、CBO 元数据获取的 Metadata Handler、自定义RelNode 和 SqlNode类型等等,同时 Calcite 底层也支持不同引擎的 SQL 方言转换。对于 SQL Planner 的优化框架,整体上 Calcite 已经搭建完成,我们可以直接自定义扩展所需要的差异化特性。下面是 Calcite 各模块的架构设计示意图:

img

上图中的所有模块都可自定义实现,接下来让我们对各模块一一进行说明:

  1. JDBC Client 和 JDBC Server,主要负责一个 SQL 的请求响应和结果返回,可以基于 Calcite 子项目 Avatica 框架来进行实现。
  2. SQL Parser 和 Validator,Parser 主要负责对一个 SQL 进行解析,生成 AST 树。Validator 主要是验证 SQL 的元数据合法性。
  3. Operator Expressions,则是将一棵 AST Tree 转换为 RelNode关系代数的计划树,这样优化器才能识别和优化。
  4. Query Optimizer是Calcite 优化器模块,有 RBO 和 CBO 优化器,即对 Query 的关系代数计划树做优化。
  5. Metadata Providers,是CBO 优化器计算 Cost 时所需元数据的提供者,包括:Selectivity(选择率)、RowCount、DistinctRowCount 等等。
  6. Pluggable Rules,Calcite 优化规则模块,Calcite 主要有:Transformation Rule(逻辑优化规则)和 ConverterRule(Implementation Rule),用户可以自定义可扩展。

以上我们是从 Calcite 模块组成视角来进行理解的,那么下面从 Calcite 底层核心源代码类调用流转逻辑来看。一个 SQL 的处理逻辑,会使用 SqlParser 将 SQL 解析为 SqlNode,使用SqlValidator 来进行 SQL 校验,使用SqlToRelConverter来将 SqlNode 转换为RelNode关系代数,使用 RelOptPlanner(具体有HepPlanner 和 VolcanoPlanner )来进行计划优化,同时可以通过扩展RelOptRule 、BuiltInMetadata 的实现,来自定义 SQL 优化器的逻辑。CalCite 这种可扩展的设计逻辑,极大的方便开发同学去自定义 SQL 引擎 Planner 逻辑,同时避免大家重复造轮子。

下图是 Calcite 底层核心代码调用流转示意图:

img

二、SQL 查询优化器概述

2.1 SQL 查询优化器的用途

SQL 作为一种声明式的查询语言,能够让很多技术以及非技术人员快速入门和掌握,用户能够使用 SQL 快速完成业务层的查询语义逻辑的编写。但单纯的 SQL 语言,是无法直接让底层的计算引擎识别和运行的。当 SQL 查询请求发送到底层数据库时,需要将 SQL 查询语句转换为底层数据库的计算引擎能够识别的模型约定定义(比如执行计划描述),最终让底层计算引擎按照预定的计算逻辑执行并返回结果。

对于 SQL 优化器的核心用途——将用户输入的 SQL 查询语句转换为计算引擎能够识别和计算的执行计划,由于最终转换的可以运行计划有很多种情形,所以优化器需要从中选取一个最优的执行计划,下发到计算引擎执行。这里所谓的“最优”既可以结合我们的先验经验来判定,同时也可以从一个执行计划使用到的物理资源进行考量,比如使用的 CPU、内存、磁盘 IO、网络 IO、CPU LRU Cache 等等。SQL 优化器的核心逻辑:就是对关系代数计划做等价转换,在不改变计划语义的情况下,尽可能最大限度对关系代数计划进行优化。

2.2 SQL 查询优化器的优化方式

常见的 SQL 优化方式有两种:RBO 优化(基于先验经验的启发式规则优化)和 CBO 优化(基于计算成本的优化)。RBO 主要是使用一些预定义的先验且有收益的优化规则集合,来对 SQL 进行优化,常见的有:常量折叠、谓词下推、列裁剪、关联子查询消除等优化规则。下图以谓词下推优化举例:

img

上图左边是原始 SQL 计划,可以看到,通过 Filter 谓词下推规则优化后,Filter 节点已经下推到了 Join 节点之下,这样能够提前对 Scan 节点的数据进行过滤,最终减少进入到 Join 算子的数据量,减少 Join 节点的计算成本。

当然,根据先验经验主义的优化方式也存在缺陷,比如在部分场景中,由于没有考虑到 SQL 在真实环境下的实际运行情况,其执行效率可能并不是最优的,所以就有了基于 Cost 的优化方式(CBO)。CBO 优化,则是在期望的物理特质下,通过对不同物理计划运行所需要的成本进行估算,使用动态规划,来选择一个计算成本最优的物理计划。一般 Cost 包括:CPU、内存、磁盘 IO、网络 IO 等等。

当然,随着技术的演进,现在在 RBO 优化阶段,其实也可以基于 Cost 来评估某些优化规则是否应该使用。这里以 Group By(聚合) 下推举例:

img

在上图中,如果 LogicalJoin 之后的基数(输出的行数)如果比 LogicalTableScan[A] 后的基数要小的话,Aggregate 不下推,其实会比下推更加节约资源。但完全进入 CBO 阶段,如果计划搜索空间过大的话,CBO 找出最优计划的耗时可能又很久。所以在使用 RBO 优化规则时,某些规则可以比较计划转换前后的 Cost ,来决定是否应用该规则。目前业界像 Oracle 和 MemSQL(SingStoreDB)在它们的优化器都已经按照这种方式进行实现。

2.3 SQL 查询优化器的框架类型

目前业界的 SQL 优化器框架类型有:Volcano、Cascades、Columbia、Orca 等优化器框架,比较主流的优化器框架为 Cascades,像微软的 SQL Server、阿里 ADB、PingCAP 的 TIDB、CockroachDB、StarRocks 这些商业化产品,其 SQL 优化器都是基于 Cascades 优化器框架的。

Columbia、Orca 这两款优化器框架都是在 Cascades 优化器基础上,做了部分改良和优化。以 Columbia 优化器框架举例,其在 Cascades 优化器基础上,对于搜索计划空间剪枝做得更好,不仅能够基于 Group 空间计划剪枝,同时也能够做全局计划剪枝,这样在一个可以接收并近似最优计划的前提下,通过剪枝来减少 Plan 空间搜索的时间,提升查询性能。Orca 则是能够作为独立的优化器在数据库系统之外运行,这样的好处在于优化器不需要和数据库系统紧密耦合在一起,但需要提供一种能够和数据库系统之间的交互通信机制来处理查询。

Cascades 优化器相对于 Volcano 优化器最大的区别在于:Volcano 优化器会先尽可能枚举所有的执行计划空间,然后再从中找出最优的执行计划。而 Cascades 优化器能够在搜索过程中,对空间搜索计划进行剪枝,使得搜索的执行计划空间不会像 Vocano 那么大,但也可以获得一个相对较好的执行计划,这样通过减少空间计划的搜索时间,来降低 SQL Planning 的耗时,从而提升查询性能。

2.4 一条 SQL 在 Apache Calcite 的优化旅程

在一个典型的 SQL 查询服务中,从用户输入一条 SQL 语句开始,到最终结果返回到 Client,一般会经过:Client 端 SQL 查询请求、服务端接收到 SQL 请求和内部作业构建、SQL 解析、SQL 校验、SQL 优化,继而形成物理计划。如果底层有自己的计算引擎,还可以将物理计划转换为执行计划,下发到计算节点并执行;如果底层计算引擎是其他引擎的话,可以将物理计划翻译成对应引擎的 SQL 方言,然后提交到对应引擎执行。

为了方便读者更具象地理解Aapche Calcite的每个模块的运作细节,本文选择了从第二种方式出发,以实现一个SQL优化改写器为例,来展开介绍一条SQL在 Apache Calcite是如何完成解析、优化与改写的。

img

如上图所示,一条 SQL 整体处理流程分为以下几个步骤:

  1. 当 Client 层发起一条 SQL 请求时,请求会到 JDBC Server 端,JDBC Server 端底层一般可以是 GRPC 服务或者 HTTP 服务,在 Calcite 中,也可以使用 Calcite Avatica 来做 JDBC 服务端和 Driver 层的代码开发。
  2. 服务端接收到 SQL 请求后,会在内部构建出一个 Job 作业请求,同时提交到内部作业服务,之后会进入到 SQL 链路处理流程中。
  3. 在 SQL 处理流程中,第一步则是将 SQL 解析成一棵 SqlNode 的 AST 抽象语法树,这个过程中会做 SQL 词法和语法的校验。之后会进入到 SQL 验证阶段,SQL 验证阶段主要对 SQL 的语义进行验证,比如查询的数据表是否存在、函数是否存在、函数参数数据类型是否匹配等等。元数据验证完之后,其输出本质还是一棵 SqlNode Tree,接下来会将 SqlNode Tree 转换为一棵RelNode 关系代数 Tree,同时进入到 SQL 优化阶段。
  4. 在 Calcite 中,RBO 优化主要使用HepPlanner类来进行实现。CBO 优化,则是使用 VolcanoPlanner来进行实现,RBO 规则和 CBO 规则都支持自定义扩展。
  5. 经过 SQL 优化器的优化,会产出最优的物理计划。但此时仍然无法最终运行,我们还需要将物理计划转化为底层计算引擎的 SQL 方言,才能进行作业的提交和计算。

更多精彩内容,欢迎关注我的公粽号: 【雷克分析】 ,关注私信发送:命令、提效、数据库、提示词、calcite、论文,有学习资料等着你 ,欢迎关注

资料信息:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/419625.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Cesium 自定义Primitive

1、为什么要自定义Primitive a、在飞机飞行过程中,如果使用entity同时绘制飞机和线的时候,会发现飞机的飞行位置和线的位置不统一,出现差距,出现脱线。 b、结合代码分析,cesium的线和飞机模型是分开渲染的,…

跨境电商与支付介绍

1、跨境电商定义和分类; 2、国际贸易清结算; 3、跨境支付; 1、跨境电商定义和分类 跨境电商业务简单说就是指不同国家地域的主体通过电子商务进行交易的一种业务模式。同传统的电商不同,交易双方属于不同的国家。因此&#xff0…

LaMa Image Inpainting 图像修复 ONNX Runtime Demo

目录 介绍 效果 模型信息 项目 代码 下载 LaMa Image Inpainting 图像修复 Onnx Demo 介绍 gihub地址:https://github.com/advimman/lama 🦙 LaMa Image Inpainting, Resolution-robust Large Mask Inpainting with Fourier Convolutions, WAC…

C++——友元

目录 友元 友元函数 友元函数使用案例 友元类 友元 友元是C提供的一种突破封装(突破类域)的方式,有时提供了便利。但是友元会增加耦合度,但破坏了封装,所以友元不宜多用。友元分为友元函数和友元类。 友元函数 友元…

SpringBoot 的基础使用与入门(总结众多文章与实践)

一:介绍 1、SpringBoot概念 从最根本上来讲,Spring Boot就是一些库的集合,它能够被任意项目的构建系统所使用。简便起见,该框架也提供了命令行界面,它可以用来运行和测试Boot应用。框架的发布版本,包括集成…

电脑DLL修复工具,一键解决计算机dll丢失

mfc120u.dll 是一个属于 Microsoft Visual Studio 2013 或相关版本的 Microsoft Foundation Classes (MFC) 动态链接库(DLL)文件。MFC 是一个用于简化 Windows 应用程序开发的 C 类库,它封装了许多Windows API 函数,使开发者更容易创建 Windows 应用程序…

C语言 vs Rust应该学习哪个?

C语言 vs Rust应该学习哪个? 在开始前我有一些资料,是我根据网友给的问题精心整理了一份「C语言的资料从专业入门到高级教程」, 点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家!!&am…

Github配置ssh key的步骤

1. 检查本地主机是否已经存在ssh key 是否存在 id_rsa 和 id_rsa.pub文件,如果存在,说明已经有SSH Key 如下图所示,则表明已经存在 如果存在,直接跳到第三步 2. 生成ssh key 如果不存在ssh key,使用如下命令生…

奇点云:SAFe框架下,我们对平台软件工程生产线做了4项改造

导读: 客户规模扩大,如何保证大数据软件产品和服务质量始终如一?几乎所有成长中的软件厂商,尤其是需要通过私有化部署交付的厂商,都会面临这个问题。正如《人月神话》中多次表明的,单纯地增加人手、扩大团队…

吴恩达deeplearning.ai:sigmoid函数的替代方案以及激活函数的选择

以下内容有任何不理解可以翻看我之前的博客哦:吴恩达deeplearning.ai专栏 文章目录 引入——改进下需求预测模型ReLU函数(整流线性单元 rectified linear unit)线性激活函数(linear activation function)激活函数的选择实现方式为什么需要激活函数 到现在…

使用SSH推拉Github代码

快速使用 ssh-keygen -t rsa -b 4096 -C "your_emailexample.com 创建ssh密钥(一直回车,不要指定目录,不要设置密码)将生成的 ~/id_ras.pub 中的内容复制到Github对应位置即可 1.SSH简介 SSH(Secure Shell&…

Python实现时间序列分析动态因子模型(DynamicFactor算法)项目实战

说明:这是一个机器学习实战项目(附带数据代码文档视频讲解),如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 动态因子模型(Dynamic Factor Models, DFM)是一种统计学和计量经济学中用于处理…

算法项目外包的收费方式

针对算法研究性项目的收费方式和注意事项,这取决于项目的具体性质、规模和所涉及的技术领域。以下是一些常见的收费方式和需要注意的问题,希望对大家有所帮助。北京木奇移动技术有限公司,专业的软件外包开发公司,欢迎交流合作。 收…

Spring Exception 常见错误

今天,来学习 Spring 的异常处理机制。Spring 提供了一套健全的异常处理框架,以便我们在开发应用的时候对异常进行处理。但是,我们也会在使用的时候遇到一些麻烦,接下来我将通过两个典型的错误案例,带着你结合源码进行深…

WEB漏洞 SSRF简单入门实践

一、漏洞原理 SSRF 服务端请求伪造 原理:在某些网站中提供了从其他服务器获取数据的功能,攻击者能通过构造恶意的URL参数,恶意利用后可作为代理攻击远程或本地的服务器。 二、SSRF的利用 1.对目标外网、内网进行端口扫描。 2.攻击内网或本地的…

Selenium自动化落地实践

01、自动化测试流程图 02、主要过程描述 1、自动化测试的切入点 开展自动化测试的时间点很关键,需要在系统已经过多版本的系统测试,达到稳定之后。 2、可行性分析 在进行项目自动化测试之前,第一步就是要确认其可行性,是否可以…

物联网与智慧城市的融合:构建智能化、便捷化、绿色化的城市未来

一、引言 随着科技的飞速发展和城市化的不断推进,物联网技术正逐步渗透到城市的各个领域,成为推动智慧城市建设的核心力量。物联网与智慧城市的融合,不仅为城市治理提供了高效、智能的解决方案,也为市民的生活带来了前所未有的便…

canvas坐标系统 webgl坐标系统 uv纹理坐标系统 原点

一、canvas原点在左上角,x轴正方向向右,y轴正方向向下,一个点对应一个像素 二、webgl原点在正中间,x轴正方向向右,y轴正方向向上,数据显示范围在[-1,1]之间,超过此范围不显示数据 三、uv原点在左…

【wpf】关于绑定的一点明悟

背景简介 软件功能为,读取一个文件夹下的所有子文件夹,每个文件夹对自动对应生成 一组 “按键四个勾选” 按键点击触发,可以发送与其对应文件夹中的一些内容。这个绑定的过程我在之前的文章有过详细的介绍,非常的简单。 这里回顾…

白话大模型② | 如何提升AI分析的准确性?

白话大模型系列共六篇文章,将通俗易懂的解读大模型相关的专业术语。本文为第二篇:如何提升AI分析的准确性? 作者:星环科技 人工智能产品部 面对AI分析落地时的数量化、准确性、泛化性等问题,让我们稍微深入了解下当前…