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

2022-04-25 15:32:54 浏览数 (1)

目录

背景

优化规则ProjectOverIntersectRemoveRule

  • matches方法逻辑详解
  • onMatch方法逻辑详解

总结

背景

这篇文章来Hive优化规则ProjectOverIntersectRemoveRule,此优化规则的主要功能是把操作符树中INTERSECT交集操作符的之上的Project投影操作符,在满足一定条件下,把Project投影操作符移除减少执行计划的执行成本。

Hive CBO基于成本优化器原理与源码解析的系列文章都是基于Hive 2.3.3版本的,支持Intersect操作符(因为Hive 1.X不支持Intersect操作符),讲解ProjectOverIntersectRemoveRule才有意义。

从SQL角度讲,带有INTERSECT交集、 PROJECT投影的这种SQL语句写法中,如果Project投影中的RexNode表达式和Intersect交集操作符中RexNode行表达式的个数和数据类型完全一致,则将Intersect之上的Project投影操作符移除。

举例说明:

代码语言:javascript复制
SELECT key, value, ds FROM (
 SELECT key, value, ds FROM src_intersect_1
 INTERSECT
 SELECT key, value, ds FROM src_intersect_2
 INTERSECT
 SELECT key, value, ds FROM src_intersect_3
) subq ;

为了说明方便,使用了SQL进行讲述,其实优化器内部使用的RelNode关系表达式构造的操作符树组成来构建的。从操作符树角度来看,最外层的Select就是顶层的Project投影操作,内部的表src_intersect_1、src_intersect_1和src_intersect_1之间的Intersect操作就是指底部的INTERSECT操作符。

变换后的SQL表示为:

代码语言:javascript复制
SELECT key, value, ds FROM src_intersect_1
 INTERSECT
 SELECT key, value, ds FROM src_intersect_2
 INTERSECT
 SELECT key, value, ds FROM src_intersect_3;

说明:因为Project投影的字段key, value, ds和Intersect的字段key, value, ds字段个数和数据类型完全相同,因此把重复的顶层的Project操作移除掉。

Hive几乎所有优化规则Rule继承了父类RelOptRule。关于RelOptRule和RelOptRuleCall相关概念。这里不再赘述,详细翻阅前期文章。

优化规则ProjectOverIntersectRemoveRule

此优化规则的matches判断方法和OnMatch等价转换部分都相对比较简单。

因为matches和OnMatch两个方法是每条优化规则的关键,这里还是做一些两个方法的简要说明

1)matches方法逻辑详解

matches方法返回此规则Rule是否可能与给定的操作数operands匹配,但是此方法的任何实现都可以给出误报,也就是说虽然规则与操作数匹配,但随后具OnMatch(ReloptRuleCall)而不生成任何后续任务。

call.rel(0)表示为顶层为Project投影,call.rel(1)表达为顶部的Intersect交集,isTrivial函数是判断project和intersect是否完全一致,包含字段个数和字段的数据类型返回boolean值。

代码语言:javascript复制
public boolean matches(RelOptRuleCall call) {
  Project project = call.rel(0);
  Intersect intersect = call.rel(1);
  return isTrivial(project, intersect); //判断project和intersect字段个数和数据类型是否完全一致。返回true,完全一致。可以移除
}

isTrivial方法实现,是比较Project和Intersect操作符的的字段,RexUtil.isIdentity返回表达式列表是否投影传入字段

代码语言:javascript复制
private static boolean isTrivial(Project project, Intersect intersect) {
  return RexUtil.isIdentity(project.getProjects(), intersect.getRowType());
}

RexUtil.isIdentity方法源码实现:

比较了行表达式列表大小和字段的个数,并且用containIdentity方法内遍历了RexNode行表达式列表元素和RelDataType行数据类型的每个元素数据类型。Litmus为当有效性测试成功或失败时调用的回调。Litmus.IGNORE选择的是忽略。

代码语言:javascript复制
 public static boolean isIdentity(List<? extends RexNode> exps,
                                   RelDataType inputRowType) {
    return inputRowType.getFieldCount() == exps.size()
            && containIdentity(exps, inputRowType, Litmus.IGNORE);
  }

2)onMatch方法逻辑详解

接收有关一条规则匹配的通知。同时此方法被调用,call.rels保存了与规则Rule的操作数Operands匹配上的关系表达式RelNode集合;call.rels[0]是根表达式。通常一条规则Rule会检查这些节点是否有效匹配,创建一个新表达式RelNode(等价的)然后调用RelOptRuleCall.transformTo(org.apache.calcite.rel.RelNode, java.util.Map<org.apache.calcite.rel.RelNode, org.apache.calcite.rel.RelNode>)注册表达式。而RelOptRuleCall用一系列RelNode关系表达式集合作为参数,对RelOptRule优化规则的调用。

代码语言:javascript复制
public void onMatch(RelOptRuleCall call) {
    call.transformTo(call.rel(1));
  } //如果Project和Intersect字段相同,则移除Project

此条优化规则的onMatch方法设计相对简单,满足了matches判断后,直接跳过表示为顶层的Project投影call.rel(0),直接把call.rel(1) Intersect操作符注册到等价集合。这样意味着把Project进行移除。

总结

优化规则ProjectOverIntersectRemoveRule相对比较简单,简单的matches方法判断满足顶部为Project投影操作符,底部为Intersect交集操作符,并两者的字段个数和数据类型完全一致,使用call.transformTo(call.rel(1))跳过顶部Project投影,把Intersect交集操作符注册到等价集合,达到Project投影移除来进行优化目的。

0 人点赞