查看原文
其他

Hive优化器原理与源码解析系列--优化规则HiveProjectMergeRule(十一)

后羿BigDataplus BigDataplus 2021-10-15

目录

背景

优化规则HiveProjectMergeRule

  • matches方法逻辑详解

  • onMatch方法逻辑详解

总结


背景


        此篇文章讲解HiveProjectMergeRule优化规则,顶层Project投影操作(相当于HSQL中的Select操作)和底部Project投影操作进行合并的优化规则,但前提是这些Project不投影相同的输入引用集。此优化规则中,Hive只实现了matches匹配方法的判断逻辑部分,不支持在RelNode关系表达式树中含有Window窗口函数或Hive各种分析函数的的Project投影操作,而相关逻辑判断和优化的等价变换的RelNode关系表达式树的OnMatch函数是直接从Calcite 优化器优化规则父类ProjectMergeRule继承而来的。

        学习和研究CBO优化器相关知识,对于初学者来说,稍微有一点点门槛。没入门之前总觉得优化器做的都是高大上的优化操作。其实优化器也做稍微熟练SQL开发者都能优化的事情,毕竟一款支持SQL数据库面对象的是各个层次开发者,所以优化器无论是简单和复杂的优化操作都得具备。就像此条优化规则HiveProjectMergeRule就像类似于一段SQL的内外层两个Select 操作进行合并减少重复操作,从而达到优化的目的。

        同样,此条优化规则也不例外,也继承自父类RelOptRule来实现的。这里先讲述一下RelOptRule相关概念。

        RelOptRule Calcite框架中的优化规则Rule的抽象类,功能就是把一个关系表达式RelNode1转换为另一个关系表达式RelNode2,它有一系列RelOptRuleOperands,其决定了此Rule是否能被应用到一棵RelNodes操作符数的指定部分section,由optimizer优化器指出哪些Rule是可应用的,然后在这些Rules规则上调用onMatch(RelOptRuleCall)方法。而RelOptRuleCall是优化规则调用,其使用一系列RelNode关系表达式集合作为参数,对RelOptRule优化规则的调用。匹配上优化规则内一系列RelOptRuleOperands操作数,也代表了优化规则Rule配上了输入参数RelNode树的某些子RelNode,可进行优化。


优化规则HiveProjectMergeRule


优化器的优化规则Rule实现,都需实现两个方法matches和OnMatch两个方法。

1)matches方法逻辑详解

        matches方法返回此规则Rule是否可能与给定的操作数operands匹配。优化器在匹配上规则Rule的所有操作数Operands之后和调用OnMatch(ReloptRuleCall)之前调用此方法。在优化器的实现中,它可能会在调用OnMatch(ReloptRuleCall)之前将匹配的ReloptRuleCall排队很长时间,matches方法提前判断这种方法是有好处的,因为优化器可以在处理的早期,把不满足匹配条件的规则放弃掉。

        判断由RelOptCall调用的优化规则Rule是否与输入参数RelNode关系表达式匹配,即此优化规则Rule能否应用到一个RelNode关系表达式树上。

当前Project投影操作中不支持一个窗口函数与另一个窗口函数的合并。即顶部Project投影操作中RexNode行表达式的序号位,对应与底部Project的相应的序号RexNode行表达式都是窗口函数,则matches返回false。RexOver继承RexCall表达式用来调用窗口Window函数的实现类,如果一个RexNode表达式是RexOver实例,则说明RexNode行表达式为窗口函数。

RexOver继承关系如下:

public class RexOverextends RexCallCall to an aggregate function over a window.

其他默认返回true

public boolean matches(RelOptRuleCall call) { //当前投影合并,不支持窗口函数 final Project topProject = call.rel(0);//顶部Project操作 final Project bottomProject = call.rel(1);//底部Project操作 for (RexNode expr : topProject.getChildExps()) {//遍历顶部Project的输入行表达式 if (expr instanceof RexOver) { Set<Integer> positions = HiveCalciteUtil.getInputRefs(expr);//返回当前字段或行表达式中索引的位置 for (int pos : positions) {//顶Project中相应字段对应的位置来查找在底部Project投影中到行表达式,判读是否为窗口函数 if (bottomProject.getChildExps().get(pos) instanceof RexOver) { return false; } } } } return super.matches(call);}

        总之,顶层Project中一个窗口函数中的字段来自底部Project中窗口函数中的字段,是不支持的。

2)onMatch方法逻辑详解

        同样,首先使用RelOptRuleCall对象rel(0)方法获取根RelNode关系表达式Project topProject,其次获取Project的子RelNode关系表达式bottomProject。

   
final Project topProject = call.rel(0); final Project bottomProject = call.rel(1); final RelBuilder relBuilder = call.builder();

        虽然在matches方法内优化规则Rule能否应用做了判断,但不会完全覆盖到,所以onMatch方法内也可做相应的判断,如果不满足条件也不会做任何优化变换而结束。

        然后分别获取的顶部和底部的Project投影操作的Permutation对象。如果对象非空并是isIdentity为true,不再做任何优化return结束。

        如果上述条件都不满足的话,则通过topPermutation.product(bottomPermutation)方法,通过分析序列化输出创建新的Permutation对象的字段Mapping(可参考前面Rule(十)何为Mapping),取出Permutation对象的字段和相应的数据类型,再使用上面push的底部Project操作子输入RelNode,然后构建器出新合并生成的Project投影操作等价变换后,注册等价关系表达式集合RelSet。

final Permutation topPermutation = topProject.getPermutation(); if (topPermutation != null) { if (topPermutation.isIdentity()) { // Let ProjectRemoveRule handle this. return; } final Permutation bottomPermutation = bottomProject.getPermutation(); if (bottomPermutation != null) { if (bottomPermutation.isIdentity()) { // Let ProjectRemoveRule handle this. return; } //通过分析序列化输出创建Project final Permutation product = topPermutation.product(bottomPermutation); relBuilder.push(bottomProject.getInput()); relBuilder.project(relBuilder.fields(product), topProject.getRowType().getFieldNames()); call.transformTo(relBuilder.build()); return; } }

        以下是继续对一棵关系表达式树是否满足匹配优化的条件判断。

        在此优化规则内,force是判断Project合并是否为强制模式,如果force=true即强制模式,即使顶层Project和底部Project完全相同,也会执行合并动作。如果force=false即非强制模式,顶部和底部Project相同,则不会再做任何优化操作。RexUtil.isIdentity方法是判断两个表达式集合的个数和数据类型是否完全一致。

if (!force) { if (RexUtil.isIdentity(topProject.getProjects(), topProject.getInput().getRowType())) { return; }}

        RelOptUtil.pushPastProject方法把顶部Project投影内RexNode行表达式和底部Project投影内RexNode行表达式进行合并成新的Project对象。

//将基于Project投影输出字段的表达式列表转换为Project投影输入字段上的等效表达式。static java.util.List<RexNode> pushPastProject(java.util.List<? extends RexNode> nodes, Project project)

        即使顶部和底部Project操作合并后生成新的Project投影操作newProjects,使用RexUtil.isIdentity判断newProjects与底部Project的输入子RelNode做一次是否相同,如果是强制模式即force=true,直接调用call.transformTo把底部Project投影的子输入RelNode注册RelSet集合内,做一次等价变换然后返回return结束。

final List<RexNode> newProjects = RelOptUtil.pushPastProject(topProject.getProjects(), bottomProject);//想等于Project进行合并。生成新的Projectfinal RelNode input = bottomProject.getInput();if (RexUtil.isIdentity(newProjects, input.getRowType())) {//如果新生成的Project和底Project的输入input是否相等。 if (force || input.getRowType().getFieldNames() .equals(topProject.getRowType().getFieldNames())) {//如果是强制模式,字段也相等,直接把底层Project子输入,注册到优化器 call.transformTo(input); return; }}// replace the two projects with a combined projectionrelBuilder.push(bottomProject.getInput());//使用了底层Project的子input push到构建器,想等于直接移除底层ProjectrelBuilder.project(newProjects, topProject.getRowType().getFieldNames());//使用合并的Project到构建器,做了合并Project变换call.transformTo(relBuilder.build());

        在最后,排除两者Project操作相同后,bottomProject.getInput()压入构建器内作为顶层Project操作的子RelNode,使用relBuilder.project方法把newProjects生成新的合并后的Project投影操作,注册到等价的关系表达式集合RelSet。

总结

        HiveProjectMergeRule优化规则的优化功能相对还较简单的,把上下两个Project投影操作(RelNode操作符树来讲的上下关系),从Sql语句来说,把内外层两个Select进行合并一个Select的优化操作过程,本篇文章从原理和源码进行解析此规则是如何实现的。

        由于笔者知识及水平有限,因此文中错漏之处在所难免,恳请各位老师、专家不吝赐教。


往期文章分享


优化规则系列

Hive优化器原理与源码解析系列--优化规则SortRemoveRule(一)

Hive优化器原理与源码解析系列--优化规则SortJoinReduceRule(二)

Hive优化器原理与源码解析系列--优化规则SortProjectTransposeRule(三)

Hive优化器原理与源码解析系列--优化规则SortUnionReduceRule(四)

Hive优化器原理与源码解析系列--优化规则SortMergeRule(五)

Hive优化器原理与源码解析系列--优化规则ProjectFilterPullUpConstantsRule(六)

Hive优化器原理与源码解析系列--优化规则SortLimitPullUpConstantsRule(七)

Hive优化器原理与源码解析系列--优化规则UnionPullUpConstantsRule(八)

Hive优化器原理与源码解析系列--优化规则ProjectOverIntersectRemoveRule(九)

成本模型系列

Hive优化器原理与源码解析系列—统计信息带谓词选择率Selectivity

Hive优化器原理与源码解析系列—统计信息之选择性

Hive优化器原理与源码解析系列—统计模块内存成本估算

Hive优化器原理与源码解析系列--统计信息中间结果大小计算

Hive优化器原理与源码解析系列—CBO成本模型CostModel(一)

Hive优化器原理与源码解析系列—CBO成本模型CostModel(二)

Hive优化器原理与源码解析系列—统计信息UniqueKeys列集合

Hive优化器原理与源码解析—统计信息Parallelism并行度计算

Hive优化器原理与源码解析—统计信息NDV唯一值数估算


: . Video Mini Program Like ,轻点两下取消赞 Wow ,轻点两下取消在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存