测试模拟数据准备:
test_table1
cust_no,name
60001,lisa
60002,tina
60003,kylin
60004,jeny
60005,john
60006,jamse
test_table2
cust_no,acct_type
60001,1
60001,1
60001,2
60002,1
60003,2
60003,3
test_table3
cust_no
60001
60002
60003
60004
60005
60007
test_table4
cust_no,cust_level
60001,1
60002,2
60003,3
60004,4
60005,5
测试环境:
由于是小表把mapJoin关闭
set hive.auto.convert.join=false;
测试sql:
select t1.cust_no as cust_no,t2.cust_no as custNO,t1.name,t4.cust_level from tmp.test_table1 t1
left join tmp.test_table2 t2 on t1.cust_no=t2.cust_no
and t2.acct_type='1'
left join tmp.test_table4 t4 on t1.cust_no=t4.cust_no
where t2.cust_no is null and t4.cust_level not in ('4','5') and exists (select 1 from tmp.test_table3 t3 where t1.cust_no=t3.cust_no);
通过查看执行计划,发现 t4.cust_level not in ('4','5')条件丢失,导致查询出来的数据不正确
错误结果:
60003 NULL kylin
60004 NULL jeny
60005 NULL john
正确的目标结果:
60003 NULL kylin
通过分析hive的参数,发现是谓词下推导致的丢失结果hive.optimize.ppd,这个参数默认是true,false情况数据量太大。跟踪代码发现生成的RS(ReduceSink)里少t2表。在谓词下推时会使用这个表别名去作为key查找这个谓词是否需要下推,key存在就去下推谓词,否则谓词不生效。
跟踪代码发现当exists时,只获取了右连接别名的第一个表,其他表都不会去遍历获取
错误代码在语义分析类SemanticAnalyzer的genSQJoinTree方法(备注hive-1.1.0版本)的7900行实现里。
错误代码段
String[] leftChildAliases = leftTree.getLeftAliases();
String leftAliases[] = new String[leftChildAliases.length + 1];
for (int i = 0; i < leftChildAliases.length; i++) {
leftAliases[i] = leftChildAliases[i];
}
leftAliases[leftChildAliases.length] = leftTree.getRightAliases()[0];
joinTree.setLeftAliases(leftAliases);
修改代码段:
if ( !joinTree.getNoSemiJoin() ) {
String[] leftChildAliases = leftTree.getLeftAliases();
String[] rightChildAliases = leftTree.getRightAliases();
String leftAliases[] = new String[leftChildAliases.length + rightChildAliases.length];
for (int i = 0; i < leftChildAliases.length; i++) {
leftAliases[i] = leftChildAliases[i];
}
for (int i = 0; i < rightChildAliases.length; i++) {
leftAliases[leftChildAliases.length + i] = rightChildAliases[i];
}
joinTree.setLeftAliases(leftAliases);
} else {
String[] leftChildAliases = leftTree.getLeftAliases();
String leftAliases[] = new String[leftChildAliases.length + 1];
for (int i = 0; i < leftChildAliases.length; i++) {
leftAliases[i] = leftChildAliases[i];
}
leftAliases[leftChildAliases.length] = leftTree.getRightAliases()[0];
joinTree.setLeftAliases(leftAliases);
}
增加当是exists时,去遍历右连接表的所有表别名,把它存放起来
在hive JRIA提的bug是HIVE-21452