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返回,秀啊!