Calcite分析 -- Convention&Converter

Calcite,version:1.26.0

 

什么是Convention

 

1. 是一种RelTrait,而且是默认必须有的RelTraitDef

2. 逻辑算子的convention为None,表示未被实现;反过来说物理算子的convention一定不会是None

在CBO优化前会把root进行convention转换,

  

改变Convention

两种方式,

显式的调用changeTraits,一般只有对于root

通过convertRule,

 

changeTraits

 

这里对于logicalSort已经注册Subset#3,

这里调用getOrCreateSubset,目的是什么?

这里注意一个参数,required=true,什么意思?

这个代表当前Subset物理属性的状态,

解释一下?比如排序是一种物理属性,由于parent算子有排序的需求,所以要求,require,当前的算子具有RelCollation的物理属性。

这里required是true,因为这里的物理属性不是因为他自己或inputs,而是被外部显式调用加上的

 

 

这里调用getOrCreateSubset,是因为traits变了,Subset是和traits紧密关联的,

所以这里生成了新的Subset,

并且这里还加入了比较复杂的converter的相关逻辑,

因为在每次Subset的traits发生变化的时候,都需要看看是否需要加入converter,

这块逻辑其实不应该加在getOrCreateSubset里面,这样很影响可读性

那么翻译一下,逻辑是啥?

首先,如果convention==None,逻辑算子,不需要conventer

其次,如果物理算子,

新创建的subset,需要conventer

已有的subset,当required属性发生变化时,需要加converter;即原先不是required,现在是,或原先包含required,现在不是

 

这里还是唯一会修改state的地方,

因为当convention改变的时候,肯定是需要生成Subset的,

逻辑,是如果convention不等于none,那么说明有convention,这里二选一,不是required,其他的都是delivered

也就是通过RelSet.add,加入一个convention不为none的RelNode时,对应的subset就会被设置成delivered

为什么?RelSet加入RelNode,大概率是因为rule生成新的算子,如果这个算子带convention,会影响到相应的subset,这个就应该算是delivered;

 

getOrCreateSubset被调用的主要的两个地方,required的设置是不同的,

1. 在changeTraits,required设为true,因为显式调用,所以就是required

2. 在RelSet.add,加入一个RelNode时,只要不是enforcer,required都是false,即大部分情况都是false

addConverters的逻辑详见,Calcite分析 -- ConverterRule

 

总之,这里changeTraits的结果就是增加一个新的traits的Subset,

注意changeTraits并不会改变RelNode的traitSet,这里仍然是LogicalSort.NONE.[0 DESC-nulls-last],

为何?在plan用Subset做input,不直接用RelNode,不用转?

 

ensureRootConverters

- 这是唯一处,显式require增加converter的地方;其他地方都是由consumer来require,但是root没有consumer

- 要求root做在的RelSet中的所有subsets,只要和root的traitSet不同的,都增加一个converter

理解,要求这样的convention,你如果不满足,就加一层converter去转换成require的convention,满足需求

 

什么是,AbstractConverter

- Converter,用于convert一个Relnode到特定的输出convention

- AbstractConverter,抽象的,所以后面需要被rule转换成可实现的关系表达式

 

 注册,有EquivRel,root

 

converter在注册的时候,

不同的地方在于,要判断一下RelSet,

Converter和他的input,就是需要被转换的RelNode,需要属于同一个RelSet

 

注册完的结果,

AbstractConverter和他的input,RelSubset#3,在一个Relset中

并且这个RelSet的Parents里面,也加上了这个Converter

  

在fireRules后,和AbstractConverter相match的rule为,

  

ExpandConversionRule

专门用于match,AbstractConverter

后面在触发的时候看看,具体做了什么

 

findBestExp

重复调用ensureRootConverters,避免没有调用setRoot,直接调用findBestExp?

这里会把AbstractConverter的input放到subsets中,避免重复加converter

这里可以看下,root.getRels,这里root是subset是无法直接get到rels的,需要找到Relset先

这里找到,rels中和subset的traitSet匹配的rels,

有意思的是,这里强行用linq4j转成Enumerable,使用了一下lambda,再转回iterator返回,秀啊!

 

posted on 2021-08-31 19:56  fxjwind  阅读(647)  评论(0编辑  收藏  举报