前言
读到了篇有用的博客,介绍了Hepplaner的调用流程,总结起来就是setRoot()将RelNode注册到Graph中(Graph的顶点叫HepRelVertex是对RelNode封装),再进入findBest()按照program一组组的执行优化规则,从Graph中取出符合的点来应用规则。
Graph
以HHepPlannerTest#testRuleClass 为例,看看Graph的变化
addRelToGraph
调用流程依旧是从setRoot() 进入addRelToGraph ,注意此刻的plan进行DFS的第一条路径应该为:LogicalIntersect -> LogicalUnion -> LogicalProject -> LogicalTableScan 下面看这条路径上的每个节点是如何注册的
LogicalTableScan
按照刚刚的提到路径进入到了最深层,因为是最底层没有input所以不会进入onCopy(oldRel, rel) 的逻辑
onCopy(oldRel, rel)是为了将HepRelVertex的input从RelNode替换为HepRelVertex
此时mapDigestToVertex 中还没有节点,拿不到等价的边,而是直接走到下面创建新的顶点和边
LogicalProject
刚刚的LogicalTableScan 已经注册,所以mapDigestToVertex 有一对KV记录着它。需要注意的是这个key是通过RelNode#getDigest 获得的,所以自己实现RelNode 的时候要注意Digest ,避免意外地被认为等价 当LogicalProject 注册进去的时候,Graph中有了2个点1条边
LogicalUnion
LogicalUnion 有两个input,刚刚只是注册完了第一个,第二个的注册其实和第一个一样就不深入了 刚刚提到 onCopy(oldRel, rel) 将relNode的input替换为Vertex ,此刻两个input都是Vertex ,Vertex 持有着原来的relNode LogicalUnion 注册完之后,有4条边5个点了
LogicalIntersect
LogicalIntersect 也有两个input,另一input注册同理不再深入,最终注册完得到的Graph 有8个点7条边 整个Graph画出来的话就是这样,边的注册顺序其实就是层序遍历的顺序
applyRules
对Graph顶点HepRelVertex 应用相应规则的时候遍历顺序可以指定,默认为DEPTH_FIRST iter拿到指定顺序排列的顶点 会尝试着对每个节点应用所有的规则
applyRule
尝试应用规则的时候,会先判断规则定义的Operand和当前的Operand是否匹配,再判断规则的附加条件 都匹配了之后会进行优化,并将优化的结果取出封装为新的顶点注册到Graph
总结
优化的时候会不断往Graph中注册新的边和点,当不再有新节点添加或者到达匹配次数的时候结束,此刻得到的RelNode被认为是最终的plan。
|