2015年6月30日星期二

记低版本Hive的left outer join Bug.

由于公司使用的是低版本的hive(0.8),同时也进行了自研发。因此线上的hive版本较低,并且存在left outer join的Bug.

Bug解释:

 left outer join(或者右外关联、全外关联)最重要的特性与原则就是主表的数据不能丢,例如有A,B两个表,都有a,b两个字段:
hive> select * from A order by a,b;
OK
a b
1 1
1 2
1 3
2 3
2 4
hive> select * from B order by a,b;
OK
a b
1 1
1 2
1 3
那么以下这个左外关联查询应该得到以下的结果:
hive> select a.*,b.* from A left outer join B on A.a = B.a and A.b = B.b;
OK
a b a b
1 1 1 1
1 2 1 2
1 3 1 3
2 3 NULL NULL
2 4 NULL NULL
但是实际情况却是,低版本的Hive在外关联上的一个重要缺陷。
select A.*,B.* from A left outer join B on A.a = B.a and A.b = B.b  where A.a =1 and B.b = 2;
上述SQL多了一条where条件。根据外关联的原则:主表数据不能丢失,即A表的数据不能丢失,当on里面的条件为真时,使用B的数据进行关联,当on里面的条件为假时,B的列全部为NULL。因此这个SQL的结果应该是:
a b a b
1 1 NULL NULL
1 2 1 2
1 3 NULL NULL
关系型数据库中验证此SQL的结果正确。
但是在Hive中结果却如下:
select A.*,B.* from A left outer join B on A.a = B.a and A.b = B.b  where A.a =1 and B.b = 2;
OK
a b a b
1 2 1 2
问题分析:
Hive在做left outer join时,首先进行join,结果集中B表对应的列会存在没有数据的情况,即NULL;然后,hive进行where条件过滤,但是此时B表的部分行的列为NULL(即A无法匹配到B表列的结果),这些行会被过滤掉,导致结果集错误。
hive的执行逻辑顺序有误,where条件会对关联后的B表列进行过滤。
正确的逻辑顺序: 过滤-->关联
规避方法:
将B表的where条件作为子查询,具体如下:(对于有分区限制的情况,也需要添加至子查询)
select A.*,C.* from A left outer join (select * from B where B.b = 2 ) C on A.a = C.a and A.b = B.b ;

1 条评论: