前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Hive优化器原理与源码解析系列--优化规则HiveProjectMergeRule(十一)

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

作者头像
用户7600169
发布2022-04-25 15:34:54
4460
发布2022-04-25 15:34:54
举报
文章被收录于专栏:BigDataplusBigDataplus

目录

背景

优化规则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继承关系如下:

代码语言:javascript
复制
public class RexOver
extends RexCall
Call to an aggregate function over a window.

其他默认返回true

代码语言:javascript
复制
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。

代码语言:javascript
复制
   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。

代码语言:javascript
复制
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方法是判断两个表达式集合的个数和数据类型是否完全一致。

代码语言:javascript
复制
if (!force) {
    if (RexUtil.isIdentity(topProject.getProjects(),
            topProject.getInput().getRowType())) {
        return;
    }
}

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

代码语言:javascript
复制
//将基于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结束。

代码语言:javascript
复制
final List<RexNode> newProjects =
        RelOptUtil.pushPastProject(topProject.getProjects(), bottomProject);//想等于Project进行合并。生成新的Project
final 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 projection
relBuilder.push(bottomProject.getInput());//使用了底层Project的子input push到构建器,想等于直接移除底层Project
relBuilder.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的优化操作过程,本篇文章从原理和源码进行解析此规则是如何实现的。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-10-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 BigDataplus 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档