Thursday, May 3, 2018

Hive带non-parttiion-filter的query自动转化为local FetchTask问题

下参数设置为minimal/more之后,对于普通的select(和其他一些cases),task会转化为local的FetchTask直接拉数,不会走mapreduce。
set hive.fetch.task.conversion=minimal; set hive.fetch.task.conversion.threshold=10000000;
但对于一个partition是p_date和p_hourmin的table,如下语句依旧转化成了一个FetchTask(bin/hive执行下面SQL后会发现在打本地log,而不是启动mr job):
select * from tbl where user_id=123 and p_date='20180501' and p_hourmin = '19' limit 10;
但上述语句的问题在于,这个partition对应的大小是2T,转换为FetchTask肯定是不合理的。
debug思路: 
1. 跟到源代码对应位置,在所有执行分支入口打log,复现问题发生时的代码走势
2. 在有问题的分支方法入口,将参数serialize到本地文件,构造问题复现环境
经过上述两步后,发现在SimpleFetchOptimizer里data.hasOnlyPruningFilter()返回的true,所以也没有走到后面的代码片段,用hive.fetch.task.conversion.threshold做判断。
继续深入看hasOnlyPruningFilter是谁写入的,发现在PartitionPruner.onlyContainsPartnCols()里,有对当前SQL filter项的判断,继续打印日志,发现上面SQL对应的expression string是"[(null and (p_date = '20180501') and (p_hourmin = '19'))]", 相当于将non-partition field变为了null传入进来,但在逻辑上并没有对null做判断。
在方法中添加如下逻辑后(即:如果有null存在,则一定为non-partition field filter, 则onlyContainsPartnCols应该返回false),上述SQL会去执行MR job,问题解决。
if(StringUtils.isEmpty(expr.getExprString()) || StringUtils.equalsIgnoreCase(expr.getExprString(), "null")) {
return false;
}
P.S. Hive: 0.23

No comments:

Post a Comment