map join
map join是将join双方比较小的表直接分发到各个 map进程的内存中,在map进程中进行join操作,这样就不用进行reduce步骤,从而提高了速度。 如果不指定mapjoin或者不符合mapjoin的条件,那么hive解析器会将join操作转换成common join,即在reduce阶段完成join。容易发生数据倾斜。可以用map join把小表全部加载到内存。在map端进行join,避免reducer处理。
left semi join
left semi join(左半连接)用于替代in/exists操作。
--in/exists
select a.id, a.name from a where a.id in (select b.id from b);
select a.id, a.name from a where exists (select id from b where a.id = b.id);
--join(效果等同)
select a.id, a.name from a join b on a.id = b.id;
--left semi join(效果等同)
select a.id, a.name from a left semi join b on a.id = b.id;
select a.id, a.name from a left semi join b on a.id = b.id and b.id > 2;
(1)left semi join子句右边的表只能在ON子句中设置过滤条件,WHERE 子句、SELECT子句或其他地方过滤都不行。
(2)left semi join只传递表的join key给map阶段,因此left semi join最后select的结果只出现左表内容。
(3)因为left semi join是in(keySet)的关系,如果右表是重复记录,左表会跳过,而使用join的话则会一直遍历。这就导致在右表有重复值的情况下left semi join只产生一条数据,join 会产生多条数据,因此left semi join的性能更高。
参考文章有示例图
sort merge bucket join
SMB目的主要是为了解决大表与大表之间的join 问题,分桶即将大表分为小表,然后Map-Side Join解决,分而治之。
对于map端连接的情况,两个表以相同方式划分桶。处理左边表内某个桶的mapper知道右边表内相匹配的行在对应的桶内。因此,mapper只需要获取右表的那个桶的数据即可进行连接 (只是右表存储数据的一小部分)。这一优化方法不要求两个表必须桶的个数相同,两个表桶的个数是倍数关系也可以。
桶中的数据可以根据一个或多个列进行再排序。这样对每个桶的连接就变成了高效的归并排序,可进一步提升map端效率
创建分桶表后开启SMB
set hive.auto.convert.sortmerge.join=true
set hive.optimize.bucketmapjoin=true;
set hive.optimize.bucketmapjoin.sortedmerge=true;
--在join两个分桶表时即可自动使用SMB join。
--从第一个表读取一个存储桶,从第二个表读取相应的存储桶,执行合并排序连接。