Calcite Version:1.26.0
ensureRegistered
getSubset,从mapRel2Subset中查询一下是否注册过
无注册调用register
equivRel不为空,需要merge的case,参考,https://www.cnblogs.com/fxjwind/p/15220576.html
register
处理一下当有equivRel的情况下,可以直接用其的RelSet
调用registerImpl
registerImpl
1. 保证Rel的所有Input都完成register,这步完成,所有input节点都完成注册
rel = rel.onRegister(this);
2. Digest
mapRel2Subset是identityHM,所以无法找到属性相同的Rel
所以这里记录下digest,用于找出equivExp,这样就可以直接返回
3. 创建新的RelSet,加入allSets,这时的RelSet是空的
4. registerClass(rel);
把rel的class和convention,加到如下的结构中,并register
5. addRelToSet(rel, set);
这个函数非常重要,
第一个,把subset注册到RelSet中,
其中RelSet.add,会调用到getOrCreateSubset
这个本身逻辑比较简单,就是如果相应的traits的subset不存在,就创建一个新的
其中有一段和converter相关的逻辑比较难理解,放到conventer的部分讲解吧。
RelSet.add -> getOrCreateSubset -> subset.add(rel) -> set.addInternal(rel) -> rels.add(rel)
看下这个调用链,印证我一直的怀疑,Calcite经常会刻意增加代码的阅读成本:-)
第一步的结果,
"select mgr, count(*) from sales.emp group by mgr order by mgr desc nulls last limit 5"
这里可以简单看一下,Calcite中的核心概念的关系,对于这么简单的一个SQL
最终生成,4个RelNode,当前都是logical算子,带limit的Sort,Aggre,Project,TableScan
这里为他们生成4个RelSubset,通过mapRel2Subset,给找到RelNode对应的RelSubset,注意这里是按地址map;RelSubSet代表一组RelTraits,比如这里的,NONE.[0 DESC...]
但如果要从RelSubSet找RelNode,就需要通过subset.set.Rel去找到,很麻烦
同时对应的生成4个RelSet,等价集合,这里就是要把SubSet(带有一组特殊物理属性,traits,的等价集合)加到RelSet中,
所以RelSet中,
包含一组等价的RelNodes,rels;
一组SubSets,subsets;
第二是propagateCostImprovements,由于加入新的subset,要计算他的cost,并且还要看看所有parent的best是不是会发生变化
这个放在单独的分析cost的部分讨论;
第三是ruleDriver.onProduce(rel, subset),由于加入新的subset,可能需要增加新的Task来explore
这个放在分析TopDown引擎的部分讨论;
6. 设置parents
就是把所有input对应的RelSet的parents中加上自己,这个是和input是反向的链接,bottom-up;input是Top-down
7. fireRules
从classOperands中拿出所有和这个class相关的operand,这是在addRule时候提前生成的,避免这里要遍历所有的operand
如果可以match,调用onMatch
最终针对这个logicalSort,fire的rules有5个,