使用Hive union remove优化器的避坑指南

举报
护城小兵 发表于 2020/06/28 09:48:44 2020/06/28
【摘要】 最近在测试Hive的时候,使用Hive的Union remove优化器遇到了一个奇怪的问题,记录下定位的过程和结果,避免其他同学也碰到同样的坑。复现方法使用版本:MRS_1.9.3 (Hive-2.3.3),MRS_2.1.0(Hive-3.1.0) 步骤:create table test_union_all(version string, rk int);insert into test...

最近在测试Hive的时候,使用HiveUnion remove优化器遇到了一个奇怪的问题,记录下定位的过程和结果,避免其他同学也碰到同样的坑。

复现方法

使用版本:MRS_1.9.3 Hive-2.3.3),MRS_2.1.0Hive-3.1.0

 

步骤:

create table test_union_all(version string, rk int);
insert into test_union_all values('5.21.01',1),('5.21.00',2),('5.20.01',3);
set hive.optimize.union.remove=true; --开启Union remove优化器
select version from (select version from test_union_all where rk <=3 ) t group by version union all select 'all' as version;

 

执行结果:

image.png

查询sql执行完毕后没有任何结果,怀疑hive.optimize.union.remove的影响,然后关闭了Union remove优化set hive.optimize.union.remove=false后执行结果:

image.png

可以查询到正确的数据。

之后对不同的执行引擎做了测试

执行引擎

使用union remove查询结果

不使用该优化后查询结果

MapReduce

结果有误

结果准确

Tez

结果准确

结果准确

Spark

结果准确

结果准确

 

优化器原理

Union remove优化器是在Hive 0.10HIVE-3276)引入,主要原理是减少对Union all子查询中间结果的二次读写,简单用图描述如下下:

image.png

 

开源相关介绍https://cwiki.apache.org/confluence/display/Hive/Union+Optimization

此优化器与编译时数据倾斜优化(HIVE-3086)同时使用效果较好,编译时倾斜优化可以针对倾斜的key单独做MapJoin,与其他key的正常Join进行union成最终结果。使用Union remove后可以去掉后面的union步骤,减少一次中间结果读写。

问题分析

回到之前的问题,从问题复现的情况看,只有MapReduce在使用的时候查询会有问题,

1)  先从开源上翻了有没有类似的问题,开源有个类似的jira HIVE-12788,不过仔细一看主要是改的hive.compute.query.using.stats后的统计信息优化器StatsOptimizator,而且对照代码,在当前的hive-2.3.3上已经合入了,排除HIVE-12788

2)  对比了开关Union remove优化器后执行计划,发现开启Union removeStage的依赖貌似有问题,如下图

image.png

Stage-1是表的TableScanGroupByOperatorStage-2是常量”all”TableScanStage-0是最后的Fetch Operator,去除unionStage-0应该同时依赖Stage-1Stage-2才对。

后来从开源上找到相关的jiar HIVE-20570Hive 4.0.0上解决了。

通过合入开源的jira单并替换环境的jar包,解决了执行计划的问题,但是问题依然没有解决Orz..

image.png

合入HIVE-20570后效果

3)  问题到这里后就没有啥思路,中间也试过DEBUG Hive执行计划的过程,以及检查MapReduce任务输出的中间结果,都没有发现哪里问题。后来没办法去查看了Hadoop内核代码,发现MAPREDUCE-1501支持遍历子目录jira中是引入了一个参数mapred.input.dir.recursive,默认为false。是不是Hive默认没有开启此开关?

之后验证了下

set hive.optimize.union.remove=true;
set mapred.input.dir.recursive=true; --Deprecation,最新参数为mapreduce.input.fileinputformat.input.dir.recursive
select version from (select version from test_union_all2 where rk <=3 ) t group by version union all select 'all' as version;

image.png

查看结果,果然对了!

此问题到这里就已经解决了,Union remove优化后MapReduce任务数据写入最终目录的子目录,在HDFS默认不开启遍历子目录开关的情况下,Hive无法查询到数据。所以要切记,使用hive.optimize.union.remove优化的时候必须设置mapred.input.dir.recursive=true

 

后续

上面分析完毕后,问题是解决了,但是有同学又有疑问了,为什么不设置mapred.input.dir.recursive=true的情况下,MapReduce引擎执行的结果有问题,而TezSpark都能正常返回结果。所以下面我们就看下这两个引擎的情况。

1)  Tez支持union是在HIVE-6362中引入,对比了Tez开启和关闭hive.optimize.union.remove的执行计划,确认了设置hive.optimize.union.remove=trueUnion remove优化是生效的。

image.png

之后检查了Tez编译执行计划的过程的代码,发现使用Tez引擎编译的时候,默认就已经将mapred.input.dir.recursive设置成了true(果然是亲生的0.0

TezCompiler#init
  public void init(QueryState queryState, LogHelper console, Hive db) {
    super.init(queryState, console, db);
 
    // Tez requires us to use RPC for the query plan
    HiveConf.setBoolVar(conf, ConfVars.HIVE_RPC_QUERY_PLAN, true);
 
    // We require the use of recursive input dirs for union processing
    conf.setBoolean("mapred.input.dir.recursive", true);
  }

所以在使用Tez的时候,只需要设置hive.optimize.union.remove=true就能正常使用Union remove优化

2)  Hive的执行引擎是spark时,比较了开关优化前后的执行计划,前后的执行计划完全一样,所以猜测这个优化是否在spark下没有效果,之后检查了Hive的代码,看到这个优化是排除了spark

UnionProcessor# transform
    // Walk the tree again to see if the union can be removed completely
    HiveConf conf = pCtx.getConf();
    opRules.clear();
    if (conf.getBoolVar(HiveConf.ConfVars.HIVE_OPTIMIZE_UNION_REMOVE)
      && !conf.getVar(HiveConf.ConfVars.HIVE_EXECUTION_ENGINE).equals("spark")) {
 
      opRules.put(new RuleRegExp("R5", UnionOperator.getOperatorName() + "%" +
                                 ".*" + FileSinkOperator.getOperatorName() + "%"),
        UnionProcFactory.getUnionNoProcessFile());

Github上的提交记录https://github.com/apache/hive/commit/a7693b6b6c953414e86bb2f968340eb28e6b8b6f

所以在使用Spark的时候,不管是否设置hive.optimize.union.remove=true,都是没有此优化。

 

结论

Hive2/Hive3在使用MapReduce引擎的时候使用union remove优化器必须要同时设置hive.optimize.union.removemapred.input.dir.recursive,使用Tez引擎时只需要设置hive.optimize.union.removeSpark引擎不支持此优化。

 

Tips

1Hive2.0.0版本之前开启遍历子目录还有另外一个开关hive.mapred.supports.subdirectories,这个开关在HIVE-11582中清理了,之后就直接使用MapReduce上的参数mapred.input.dir.recursive来控制了。

2)开源在Hive 4.x上默认把MapReduce上也开启了mapred.input.dir.recursiveHIVE-12812


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。