8. Hive JOIN
写join查询时,需要注意几个关键点:
1)只支持等值join,因为非等值连接非常难转化为MapReduce任务
示例:select a.* from a join b on a.id = b.id是正确的,然而:select a.* from a join b on a.id>b.id是错误的。
2)可以join多个表,如果join中多个表的join的列是同一个,则join会被转化为单个MapReduce任务
示例:select a., b., c.* from a join b on a.col= b.col1 join c on c.col= b.col1被转化为单个MapReduce任务,因为join中只使用了b.col1作为join列。
但是如下写法会被转化为2个MapReduce任务。因为 b.col1用于第一次join条件,而 b.col2用于第二次 join
select a.*, b.*, c.* from a join b on a.col= b.col1 join c on c.col= b.col2;
3)join时,转换为MapReduce任务的逻辑
reduce会缓存join序列中除了最后一个表的所有表的记录(具体看启动了几个map/reduce任务),再通过最后一个表将结果序列化到文件系统。这一实现有助于在reduce端减少内存的使用量。实践中,应该把最大的那个表写在最后(否则会因为缓存浪费大量内存)。
示例:
a. 单个map/reduce任务
select a.*, b.*, c.* from a join b on a.col= b.col1 join c on c.col= b.col1
中所有表都使用同一个join列。reduce端会缓存a表和b表的记录,然后每次取得一个c表的记录就计算一次join结果;
b. 多个map/reduce任务
select a.*, b.*, c.* from a join b on (a.col= b.col1) join c on (c.col= b.col2)。
第一次缓存a表,用b表序列化;第二次缓存第一次MapReduce任务的结果,然后用c表序列化。
4)left semi join
经常用来替换 in和exists。
如,select * from a left semi join b on a.id = b.id;
相当于select * from a where a.id exists(select b.id from b);但这种方式在hive中效率极低。