calcite 概念和架构

1. 前言   

        Flink使用Calcite构造SQL引擎,那么他们 是怎么合做的? drill, hive,storm 和其余的一干apache 大数据引擎也用calcite , 那么对于同一个sql 语句(statement) , 不管复杂简单与否,他们和Flink产生的执行计划是否是同样的? 若是不同, 区别是怎么产生的? 应该在哪里实施优化和发力?优化的手段和原则有那些,等等?   本文不会对calcite 面面作具到的介绍,重点是SQL执行计划的优化框架,流程和策略, 对执行计划进行优化是calcite 的主要业务。为了有助于理解优化框架,对于必要的概念会有介绍, 好比关系,关系代数,关系演算,等价原理,谓词逻辑等。java

 

2. calcite 架构

 
 
图-1 calcite 使用场景
 
       如Calcite的官方论文 (见引用1, 发表于于 SIGMOD’18, June 10–15, 2018, Houston, TX, USA)所定义, calcite 是一个可以链接异构数据源,并运行优化的查询计划的基础框架 。Cacite 提供查询处理须要的三大功能:查询语言,查询优化和查询执行。 可是calcite 并不想作这样“one size fit all " 的框架, 它提供足够灵活适配接口, 使外部系统 (数据源(或称存储系统),或查询处理系统)可以选择合适的场景与它适配 。calcite 支持的场景主要有两种, 如上图描述。
       在场景1中,calcite 做为独立运行的进程,后台经过适配器与外部的存储系统链接,前台经过JDBC 接口 使用SQL 语言通用户交互 。在这个场景里,calcite 做为一个中间件,为一些没有或缺少友好的查询语言的存储系统(好比HBase, Cassandra, Kafka, ES, Redis) 提供查询语言(好比SQL)。 calcite在 内部将用户提交的查询优化并运行再本身的进程里,并在优化的过程当中将适当的部分下推给存储系统 。好比Cassandra 有部分关系扫描(tableScan), 过滤(Filter), 投影(Proction) 和聚合(Aggregation)的能力, calcite 能将相应关系表达式翻译成Cassandra 的语言发送给它并返回结果。对于 Cassandra 不具有的能力,好比链接( join),这部分关系表达式在calcite 里运行 。固然这儿场景并非calcite 擅长的,由于query 执行不是它所擅长的。
       在场景2中,calcite 做为嵌入式的组件运行在一个查询引擎里。这些查询引擎用本身的方式链接后台数据源,并使用本身的集群用分布的方式执行查询。  查询引擎善于获取数据和执行查询,须要calcite 提供查询语言和优化查询的能力 。 这个场景的例子有Hive , Flink, Drill , Storm 。 以 Flink 为例, 它的框架里有算子链接各样的异构数据源用于数据的获取和发布,不管是数据流仍是数据集。  它也有丰富的算子将讲这些数据过滤、放大、缩小和变形用于各类各样计算需求。他须要一种对用户友好的, 对于批流数据语义统一的查询语言,以便于用户编排查询做业流程,通过优化器后后, 做业可以最小的代价运行在Flink集群中。 场景2是calcite 最受欢迎的和最擅长的场景, 相比查询执行, 链接数据源, calcite 更擅长的是制造查询语言,解析查询, 和查询优化 。为何这么说呢 , 那就要看看 它的架构了。
 
图-2 引用1中calcite 官方论文中的架构图。
 
     绿色框框QueryOptimizer (优化器, 也称Planner, 好比HepPlanner, VolcanoPlanner)是calcite 的心脏和大脑,它接受查询计划,输出优化的查询计划 。
     蓝色的框框是优化器的输入和输出和各类适配器,包括Opeator Expressions (输入的原始计划,中间结果和最后输出的计划), MetadataProvider(提供元数据的组件,好比对优化规则用的统计信息(RowCount of table, Distinct RowCout/min/max of a column , etc )  还有pluggable Rules (优化规则, 利用关系代数或关系演算的等价关系,优化执行计划,使之更够最快速的执行)。这三个组件是calcite 可扩展部分,所以与外部系统有链接 。
     黄色框框(Data Processing System, 简称DPS)与蓝色框框有虚线链接,是DPS 对calcite 的扩展部分。  这里的 Data Processing System所指的就是场景2里的查询引擎。它经过扩展metadata provider 和 pluggable rules , 向优化器提供更准确的元数据信息,更适合的代价模型, 更高效的优化规则, 利用calcite 优化器产生最优化查询计划。SQL parser and validator, 是Calcite的SQL 语言的解释器, 它将用用户用SQL语言编写的查询解析称Opeator Expressions , 并验证它的合法性 。  
       Opeator Expressions是一种用于表示关系代数表达式的树状数据结构。解释器将SQL 查询解释成关系代数表达式, 以后优化器调用规则将其修改成最优表达式。优化规则会根据有关系代数的等价原理将表达式变形从而使表达式的代价下降。但如何判断代价是否下降? 办法有两种:一种是根据经验,一种是根据代价模型。根据经验学名称作启发式(Heuristic )模型, 根据代价模型估计的,学名叫火山模型。 相应的优化器也被称做启发式优化器和火山优化器(HepPlanner, VocanoPlanner)。         代价模型的量化计算是根据从metadata provider获取关系及关系运算的元数据,再辅以量化模型的计算。元数据一般指的是一个关系(table)和关系运算(projection, filter, join, aggregation, etc)产生关系的统计数据:如关系的row count, 某个份量的 distinct count, min, max 等 。DPS 会扩展Calcite 逻辑关系表达式产生“物理”关系表达式, 而这些扩展的表达式也会输入给优化器, 利用规则继续优化 。 
        Expression Builder 是一种绕过SQL解析,直接生成关系表达式的工具。 这种方式适用于单元测试,就不作展开展开介绍了。
 
图-3 calcite 交互数据流
 
       用数据流图的方式描述一下calcite 和Data Processing System 的交互, 如上图所示, 应该更容易理解 , 为何一个大数据处理系统更喜欢在场景1里面使用calcite 。优化器是从calcite的核心是不变的地方。 Rules, metadata, 和operator 是优化器依赖的帮手, 但都是可扩展的部分  。 回答在前言里的问题, 有那么多的大数据系统使用calcite, 相同的sql 查询通过calcide 优化器产生的计划会同样吗 ? 答案是否认的。 缘由是要看各个大数据系统里扩展的Operators, metadata provider , 还有新的规则和应用的顺序 是否相同等等 。不一样的扩展,产生的关系表达式确定不同。 扩展作的更优秀, 优化的结果就更优秀。 好比Metadata Provider提供的关系运算统计数据是一种估计, 除了最底层的TableScan的代价估计是相对准确的, 别的运算的估计都是有偏差的 。 偏差越小,规则运行的越准确, 反之则否则 。
 
 

3. 一些关系的概念

Calcite 只支持于关系型数据模型(不支持层次,网状,对象数据库的模型), 那么什么是关系型数据库呢 ? 建议读一下引用5中的那本书 ,虽然我也没读完 。下面解释一下一些比较容易混淆的概念 。程序员

关系:关系一词来自离散数学里的集合论,根据维基百科的的定义,给定任意集合A和B,若笛卡尔乘积),则称R为从A到B的二元关系,特别在A=B时,称R为A上的二元关系。若是一个有N列的二维表, 每一列的取值范围为Ai  则该表是定义在A1x..Ai..xAn上的N元关系。可见,关系(Relation)是N元有序序列的集合关系在数据库的概念里称做表(Table),关系的每个有序序列叫作元组或行(Row),  元组的每个量叫份量或列(Column)。算法

关系模式(Schema):是对关系或表的描述。包括关系名称(Table Name),列名以及列的定义域(Domain)。sql

关系模型(Model):指的是一系列关系模式的集合, 概念上对应数据库。数据库

维度(Dimension):一般是指列离散定义域的列。定义域上的每个值称为基(cardinality), 一个关系已经使用的全部的基的个数成为基数 (cardinal number) , 也就是 distinct count , 也成 NDV (Number of Distinct Value) 。express

 

关系代数:是由 Edgar F. Codd提出一种利用具备良好语义的代数结构用于对数据建模和定义查询的理论。代数结构是在一种或多种运算下封闭的一个或多个集合,那么关系代数在闭合关系上的良好语义的运算的集合。通俗的说,关系代数是一种经过由代数运算和输入关系组成的表达式来表达输出关系的理论。 好比 图-3中,SQL 产生的关系能够多个树形的表达式表示,树的形状和节点的排列顺序表明运算的过程(从下到上) 。关系代数是面向过程的。
关系演算,是另一钟表达关系的理论, 他是以数理逻辑中的谓词演算为基础,用描述和声明的方式表达关系 。好比关系代数表达式用一系列代数运算来表示最终的产生关系,而关系演算则用声明形式的表达式描述一下最终的关系定义 。每个关系代数的表达式,都有对应的等价的关系演算表达式(Codd定理), 但反之则否则。关系演算和关系代数都来自关系模型理论。
SQL语言:是关系代数和关系演算的实现。 好比运算都来自关系代数, 运算里谓词都来自关系演算 。 如今大多数人都说SQL是一种声明式的语言,有点道理但也不全对。演算部分是声明的,代数部分是过程的。 好比一个equal join , join 是代数规定结果是一个笛卡尔乘积。 equal 是演算定义了目标关系里保留的是双方的键值要相等。 这个声明给了关系表达式的实现者能够经过hash join, 或sort merge join 优化 这个equal 。
Operator Expression : 指的是表达关系代数和关系演算的表达式, 在calcite 中由一种树状结构来表示 。它取这个名字的缘由是树中全部的节点都有相应的操做符来表示, 包括输入和输出关系(TableScan, Sink )。我更喜欢把它叫作关系表达式:表达关系代数和演算的表达式 ,或由做用在关系上的运算组成的表达式。在优化的过程当中,最原始的树状的数据结构会转化成一个图, 由于一些子计划能够重用的,重用的子计划和原计划会使用相同的节点实例,就像一个能够重入的函数能够被调用屡次,但返回的数据是相同的。一个节点有多个parent, 就变成了不在是一棵树了。  比如SQL中的CTE, 若是上游的谓词没有下推,它是一个很是独立的存在,能够单独优化,造成一个比较独立的子计划和子表达式。 若是该子表达式被使用屡次,他在图中就会成为多个上游节点的子计划。物化视图也是一个例子。 计划图是一个有向无环图(DAG),也就是一个关系只能做为另一个关系的输入,不能做为自身的直接或间接输入,树是有向无环图的特殊性形式,因此把优化后关系表达式称为计划图比较合适 。
还有一点要注意,当咱们谈论计划的时候, 计划图是一个向下生长的DAG, 根节点是Sink, 叶结点是TableScan 。 上游,下游, 上推, 下推, 是对应从根节点先下的方向。当咱们谈论做业流(jobGraph)的是,上游,下游对应的是数据流向。

 

4. calcite的概念

       上一章的概念说了这么多, 感受就是为了解释什么是Operator Expression(关系表达式) 。这个概念很关键, 它是优化器操做的数据结构, 它通过优化规则的修剪和雕琢, 和元数据提供者养分的滋润,成为最终的最优(代价最小)结构。若是仍是很差理解, 那就先抛去那些虽严谨但晦涩的数学概念, 能够把一个关系表达式想像成一个做战计划, 好比著名的官渡之战。 若是曹操在官渡和袁绍死磕, 做为原始的做战计划,也有可能也会获胜,毕竟有官渡河天险可守。可是代价会很高,毕竟袁绍的兵力数倍于曹操,正面做打败率较低。因而曹操优化了原始计划,首先不主动出击,坚守官渡,而后 偷袭乌巢,烧了袁军的粮草,致使袁军军心大乱,仓促攻曹,最后致败。曹操用最小的代价大败袁绍于官渡,他的做战计划里的关键步骤是奇袭乌巢和坚守官渡。惋惜袁绍白白拥有10万大军,和五子良将张颌,占尽优点,但却一败涂地。袁绍最大的错误就是使用了错误的计划, 信任千古奸人 郭图,这我的不只害袁绍, 袁的两个儿子也都被他害死,最后被曹操斩杀 。不得不说,曹操不管是对官渡之站的计划,仍是对郭图的计划都是最优的。
     若是作一个粗糙的类比,曹操的大脑在至关于calcite 的启发式优化器,他手下谋士的计策就是Plugable rules ,好比荀攸突袭白马,荀彧的坚守官渡,许攸的奇袭乌巢,进攻、退守是关系代数里的运算符, 白马,乌巢,官渡这些地名至关于关系,那么行军路线就构成了一个计划图,如同关系表达式的计划图同样。做战计划依赖主将的智商和经验判断来计划的优劣,曹操雄才大略是不世的英雄豪杰,比起袁绍要聪明数倍, 他的判断天然准确率比较高。可是也有判断失误的时候啊,好比赤壁之战,依赖智商并不老是一个好办法。Calcite 的优化器要依靠元数据提供者的数据和代价模型用量化的指标来判断不一样计划的优劣,在统计上应该是更准确的。那么回到一个程序员的思惟里,优化器具体是怎么工做的呢 ?
先看下callcite 对外开放的接口。
 
 
图-4 来自引用7中, Calcite API and SPIs
概念比较多, 用一个表来解释一下吧。
 概念  解释  例子
 RelNode 关系代数中的关系和运算的基类。RelNode 有不少继承者, 见举例。 TableScan对应一个数据源的一个关系,Filter对应Filter运算 。Filter有一些系列的继承者, 每个继承者对应一个CallingConvention, 也对应一个优化阶段的使用的数据结构 。 好比Join<-LogicalJoin<-FlinkLocalJoin<-FlinkBatchExecJoin, FlinkExecStreamJoin 。
 RelDataType  表明域,是关系中列的定义域 整数,日期,浮点数,定点数,字符串
 RexNode  表明Project里Filter中表达式 好比下面关系里一个份量(InputRef),一个常量值(Literal),一个或多个份量函数(RexCall, 加、减、乘、除、CAST 等)
RelTrait 表明关系运算的物理特性,这个应该是calcite 里最让人迷惑的概念了。但Trait, set, subset 是 volcanoPlanner 最依赖的概念。
关系的物理特性是跟关系代数没有关系的一些特性,因此只有跟物理执行系统比较临近的关系运算才会有物理特性,好比FlinkBatchExecFilter 有物理特性, 它是被翻译成FlinkJobGraph的输入计划的节点类型。而LogicalFilter观彻底逻辑上的关系观念,所以不会有任何物理特性。
Calcite 有三种类型的特性, 类型叫作TraitDef 。
  • 关系某个列的排序方式(collation):数学上的关系一个N元元组的集合,是不关心顺序的, 因此关系(元组)的顺序做为一个物理特性存在。 既然和关系无关,那么Calcite里为何有sort操做符? 这个是表达式扩展或是迁就SQL的结果,SQL里有一些跟关系无关的操做,好比order by, distinct 等等, 虽不符合关系的定义,但这里上计算机世界,不是纯数学的, 就把关系看成是一个泛化的概念吧。原始的关系运算就6种,后来一些经常使用的就被填补进来,好比sort,aggregate, window, expension 等。即便计划里有sort操做符, 提早作排序,仍是是等到sort节点在排序,也是VolcanoPlanner优化考虑的选择。有时候即便计划里没有排序,排序也会使总体计划加速。 Spark的join都是用sort-merge join 正是基于这样的考虑。
  • 关系元组的发布方式(Distribution)。这个代表关系元组发布给jobGraph中的下游节点的方式。是广播出去的, 是本地forward过去,仍是异地 Shuffle过去的, 等等。
  • 调用习惯(Convention) 。前面两个特性都是关系的行和列上的物理特性,Convention 表明查询系统(也就是前面所说的DPS)的物理特性。Calcite 里面的规则大部分的规则都是由HepPlanner调用的,只有当Convention变化的时候,才会使用VolcanoPlanner 。

  •  Collcation能够是升序,严格升序,降序,严格降序,汇集。参见RelFieldCollation .
  • Distribution 能够是单一的,哈希的,分范围的,随机的,轮换的,广播的,任意的。参见RelDistribution 。
  • Convension: calcite的 JDBCConvention, Flink的LOGICAL, BATCH_PHYSICAL, STREAM_PHYSCIAL。
好比Flink中的节点BatchExecJoin在BATCH_PHYSICAL 调用习惯中的运算节点。
最初的关系表达式中的join用calcite LocalJoin表示,在LOGICAL convention 中用FlinkLocalJoin, BATCH_PHYSICAL convention 中用 FlinkBatchExecHashJoin。一个在Flink优化的join节点会有随着convention 改变可能有以下的变形。
LogicalJoin --> FlinkLogicalJoin--> FlinkBatchExecHashJoin。
 AbstractConverter

当关系表达式的 Convention 发生变化的时候, VolcanoPlanner 会在Relset 里建立Relsubset 表明这种traits, 随后建立AbstractConverter用于转化成真正的表达式。 ExpendConventionRule 配备AbstractConverter, 将它转化成合适的节点, 好比 BroadcastExchange, Sort 等 。 参考FlinkExpandConversionRule, 
calcite: AbstractConverter, Relset.addAbstractConverter。

 RelOptRule  全部的优化规则的基类, 它构造函数第一个参数就是关系运算的类型(好比, Join, Filter 等),(还有一些别的, 不展开了)。当Planner 遍历表达式图的每个节点时,他会调用匹配这个节点类型的规则 。除了匹配类型,VolcanoPlanner 还会给规则设置优先级,级别高的会别先调用。每个规则有两个函数: matches() 继续深度判断改规则是否真的应该调用。 onMatch 执行规则实际的动做:根据测量增、减、改变、升级表达式的节点。
优化规则有的会经过元数据提供者查询元数据信息,从而作相应的措施。有的不会。从规则的角度来看,planner 都是无区别的。 因此除了少许的例外(好比前面提到的ExpendConvensionRule),大部分均可以被HepPlanner 和 VocanoPlanner 调用的。 


 例子有不少, 好比有名的谓词下推,子查询替换,join-recorder, 常量替换等。google里搜索一下, 会不少介绍 。
想看全面的, 请参考
org.apache.calcite.rel.rules里面的规则, 或
FlinkBatchRuleSets.scala里面的使用的规则。
RelMetadataProvider
RelOptCost
 前文屡次提到的统计数据提供者,他是一个能handle不一样统计类型数据的handler的集合。好比 RelMdRowCount是提供关系运算产生的rowCount估计, RelMdDistinctRowCount 提供某个列的cardinal number 估计 。RelMdSelectivity 提供关系运算后的rowcount 原来的比例 估计。
RelOptCost是代价模型, calcite 的代价模型是对关系的行数,一般是考虑IO(disk IO + network IO) 和CPU使用率, memory, 和 关系规模(rowcount)的一个综合衡量。
Calcite 里有DefaultRelMetadataProvider 提供了各类Handle 缺省计算方法。ReflectiveRelMetadataProvider 因为接受DPS端实现的Provider , 好比 Flink里实现的FlinkDefaultRelMetadataProvider .
还有一个JaninoRelMetadataProvider, 看起来是经过动态编译的生成Provider ? 

Handler的元数据的估计算法请阅引用5的第13章。
Schema
Table 
Lattice ,Tile
 Schema和table的概念全面说过。
Lattice(格) 是除了关系、关系代数以外,另外一个来自于数学领域的名词。看起来calcite 是真的很想提高广大数据程序员的数学格调。
格同关系代数同样是一种代数结构(集合+一种二元关系),集合的成员的二元关系是反自反, 和传递的, 并且这个关系有明确的上下界, 则称这种代数结构为格。 很抽象, 能够看引用8中的哈斯图理解 。{ x, y, z }的冪集包含偏序排序就是一个格。 
这个和多维cube聚合计算的物化视图的结构很像。 物化视图里的每个顶点都是一个tile , 最上面的tile 包含了全部的维度, 最下面的维度为空, 维度集合以及包含关系组成了一个格。 格从上到下是是降维的过程,则低维聚合计算可由高维聚合导出 。因此lattice , Tile 是为 物化视图引入的, 只不过换了一个文艺的名字而已 。
物化视图是一个预计算的结果,物化在硬盘或内存里,若是把查询计划里可以利用物化视图,执行的很定会飞快 。
 

 

来自引用8apache

HepVertex
HepProgram
HepPlanner

HepVertex是HepProgram里用于组成计划图的顶点。HepProgram 是一些优化规则的集合,HepPlanner 利用HepVertex创建将计划树转化成计划图, 而后利用HepProgram按照必定顺序遍历其中的优化规则。
HepPlanner 调用流程如右侧代码所示。
  • 调用SetRoot 用HepVertex创建全新的计划图,
  • changeTraits, desiredTraits为空
  •  调用findBestExp用迭代的方式,用预先设定的顺序(好比BOTTOM_UP),遍历全部匹配的规则,优化计划图。
HepPlanner的寻优 是一个一种贪心的算法,就是当前迭代步会用上一次迭代结果的做为当前最优结果继续优化,若是上一步作错了,下一步也会错下去。只有将迭代运行屡次,才有可能避免改正错误。


  
//build program
val builder = new HepProgramBuilder()
builder
  .addMatchLimit(10)
  .addRuleInstance(SubQueryRemoveRule.FILTER)
  .addRuleInstance(SubQueryRemoveRule.JOIN)
  .addMatchOrder(HepMatchOrder.BOTTOM_UP)
val hepProgram = builder.build()
//create planner
val planner = new HepPlanner(hepProgram, ...)
//build new operator expression graph
planner.setRoot(root)
planner.changeTraits(desiredTraits)
//apply rules in programs to optimize the operator expression
planner.findBestExp

  

 Relset
RelSubset
VolcanoProgram
ValcanoPlanner
 RelSubset 表明一个目标物理特性, 好比BATCH_PHYSICAL.Broadcast.ANY, 表明一个BATCH_PHYSICAL convention 等价 子计划,行发布方式是广播, 列排序方式为任意。BATCH_PHYSICAL.Hash.ANY,是另为一个subet 。 
 
Relset 是全部具备不一样物理特性的等价的RelSubset的集合这些, 好比BATCH_PHYSICAL.Broadcast.[]和 BATCH_PHYSICAL.Hash.[]是等价的。

Relset 仍是全部等价关系的集合,好比HashExchange+SortMergeJoin,HashExchange+HashJoin, BroadcastExchange+Hash, ASC sort + SingleExchange+Hash 都是等价关系表达式。


RelSubset 会在从等价关系集合里选择符合自身trait的最便宜的做为他的best 。从上到下的best组成最终的计划图 。

VocanoPlanner 运行流程和HepPlanner相似。
  • 调用SetRoot 用RelSubset, Relset创建新的计划图,
  • 调用changeTraits, 设置root的traits , 并沿着计划图将traits向下传递,每一层都要根据关系运算的特色向下提升须要的trait .
  • 调用findBestExp, 用动态规划的方式,总体上从下到上建立符合trait要求的关系表达式,在其中选择最便宜的填入subset中, 并将cost 向上传递 。
  • 当全部每一层的subset 的best都计算完成从到下,作广度优先搜索便可获得最优的计划。


 

5. 优化器流程

 

HepPlanner 的寻优流程很简单,setRoot重建planGraph, findBestExp 就是按照指定的顺序将HelpProgram里的规则触发一遍。 若是担忧有问题贪心算法的问题,能够将这两步多作几回。网络

 

VocanoPlanner 的寻优流程如前所述。 TraitSet 一般包含了 Convension, distribution,  collation 三个维度 , 这三个维度不一样的基的组成的组合(subset)都是等价的可是cost不相等,但并非代价把最低的subset 输入给上游总代价就会最低的。最低的代价须要综合考把虑上游和下游的状况,寻找最搭配的搭档。因此这个寻优过程须要一个动态规划的方式来求解。在使用动态规划(也就是递归的方法, volcanoPlanner 的命名就来自这里吧 )求解以前, 咱们须要把各类可能的计划的每一层的知足须要trait的subset, 以及对应关系求出来。 而知足要求的subset, 并且在考虑到输入的组合,状态转移公式大概以下。数据结构

 
BestExp(subset)) =  argmin( cost(rel1 ), cost(rel2), ... )
cost (rel ) = algoCost(rel.self) + cost(BestExp(rel.input1)) + cost(BestExp(rel.input2)) 

 第一行中,rel1, rel2  是知足traits 的等价表达式,表示当前subet的最佳表达式是他们之中里cost最低的表达式。架构

   第二行中, 表示表达式的cost 等于最上层节点自身算法代价估计 和下层输入subset的最佳表达式向上输入的累计的综合代价 。TableScan 的下层输入就是磁盘IO的代价,底层关系的RowCount相关 。这里的加号表明代价计算要综合考虑的因素并非简单的算数相加 。好比hashJion和sortMergeJoin自身算法的代价不同(CPU, 内存代价), join的两路输入方式不一样代价不同(IO代价)。

 
举个例子 :
SELECT * from store_sales join date_dim on store_sales.ss_sold_date_sk = date_dim.d_date_sk and date_dim.d_year=2002
1  
这个表达式里主要有一个HashJoin 和两个TableScan 组成, 若是对HashJoin 的 requriedTraits 是 BATCH_PHYSICAL.ANY.[],  HashJoin 对store_sales 和 date_dim的要求分别是BATCH_PYSICAL.forward.[] 和 BATCH_PYSICAL.broadcast.[], 那么上面的公式如下的形式 。
 
BestExp(join.BATCH_PHYSICAL.ANY.[]) = argmin( cost(shuffledHashjoin), cost(broadcastHashJoin), cost(shuffledSortMergeJoin),... )
cost(broadcastHashJoin)= cost(BestExp(tablenscan_store_sales.BATCH_PHYSICAL.forward.[])) + cost(BestExp(tablenscan_date_dim.BATCH_PHYSICAL.broadcast.[])) + algoCost(HashJoin)

 

相似的过程能够求出 cost(broadcastHashJoin), cost(shuffledSortMergeJoin) 。
Broadcast join 极大的减小了网络和磁盘IO, cost 确定是最低的 , 最终Broadcast join表达式会选为join 层知足要求的subset 的最佳关系表达式 。
 
从上面的转移公式能够看到, required traits 是从一般从上向下传递的(也有自我要求的) ,好比join对下游的广播方式的要求, 全局排序要求下游以single 方式发布数据的要求等。   cost是从下先上传递的, 没有下游已经肯定的关系,上游是没法计算代价的 。在向下传递traits 的过程当中, calcite 建立AbstractConverter表明 目标traits 临时节点, 以后再ConventionExpansionRule 将 AbstractConverter 转化成实际的关系。好比AbstractConverter.Broastcast.[] 建在TableScan上面, 目的是想让tableScan以广播方式输出, ConventionExpansionRule最终会将这个表达式变成BroadcastExchange+TableScan 。当TableScan的代价估计会沿着Exchange向上传递, 上游关系的代价也得以计算, 以此类推 。
VolcanoPlanner 将与节点匹配上的  ConventionExpansionRule 和其余的ConverterRule 都放在优先队列里。因为新的relSubset建立时, AbstractConverter才会建立,以后触发ConventionExpansionRule 与之匹配和放入队列, 用以以后建立Exchange 和 sort 节点。这个和其余的ConverterRule 不一样, ConverterRule 是匹配旧的Convention 的结点(好比LogicalXxxxx), 他们在节点注册的时候(setRoot)就已经入队。优先队列里的成员都有优先级,级别高的先被调用, 这样能保证那些ConverterRule 先于ConventionExpansionRule 调用。
 
 
图-5 VolcanoPlanner

画个图表示一下 relSet, relSubset, 和besExp 还有trait之间的关系吧, 还有这个相似火山喷发的形状。

 

 

7. 引用

 

 序号  描述  连接
 1  Calcite 论文 dl.acm.org/doi/10.1145/3183713.3190662
 2  Calcite 官方文档  calcite.apache.org/docs/
 3 关系代数 en.wikipedia.org/wiki/Relational_algebra
 4 关系演算  https://en.wikipedia.org/wiki/Relational_calculus
 5  数据库系统概念第6版 Abraham Silberschatz 等著  
 6  官渡之战  https://zh.wikipedia.org/wiki/%E5%AE%98%E6%B8%A1%E4%B9%8B%E6%88%98
 7  SQL on everything, in memory by Julian Hyde  www.slideshare.net/julianhyde/calcite-stratany2014
 8  哈斯图  zh.wikipedia.org/wiki/%E5%93%88%E6%96%AF%E5%9C%96
相关文章
相关标签/搜索