1. Common Join
Common Join 是最稳定且默认的Join算法,通过 MR Job 完成 Join 。
需要注意的是,在三个表的 Join 关联中,如果这三个表的关联 key 相同,那么 key 就被在shuffle 后被发送到同一个 Reduce Task 中,因此三表关联时,可能会启动2个 MR Job,也可能会启动1个 MR Job。
2. Map Join
Map Join 通过两个 Map 任务,在 Map 阶段完成 Join 关联。
该算法适用于大表关联小表,小表叫 build table,大表叫 probe table。Hive 在解析带 join 的 SQL 语句时,会默认将最后一个表作为 probe table,将前面的表作为 build table 并试图将它们读进内存。如果表顺序写反,probe table 在前面,引发 OOM 的风险就高了。
第一个 Map Job 启动本地任务读取小表中的数据,首先将其制作为 Hash Table,再将其上传到分布式缓存(HDFS)中,第二个 Map Job 将小表读取至内存,并且扫描大表,在 Map Job 中完成两表的关联,因此可以不走 Reduce。
当 Hive 执行 Join 时,需要选择哪个表被流式传输(stream),哪个表被缓存(cache)。Hive 将 JOIN 语句中的最后一个表用于流式传输,因此我们需
要确保这个流表在两者之间是最大的。如果要在不同的 key 上 join 更多的表,那么对于每个 join 集,只需在 ON 条件右侧指定较大的表。
## 是否根据输入小表的大小,自动将reduce端的common join 转化为map join,将小表刷入内存中。
## 对应逻辑优化器是MapJoinProcessor
set hive.auto.convert.join = true;
## 刷入内存表的大小(字节) 25M = 2G
set hive.mapjoin.smalltable.filesize = 25000000;
## hive会基于表的size自动的将普通join转换成mapjoin
set hive.auto.convert.join.noconditionaltask=true;
## 多大的表可以自动触发放到内层LocalTask中,默认大小10M
set hive.auto.convert.join.noconditionaltask.size=10000000;
也可以手动开启Mapjoin:
--SQL方式,在SQL语句中添加MapJoin标记(mapjoin hint)
--将小表放到内存中,省去shffle操作
// 在没有开启mapjoin的情况下,执行的是reduceJoin
SELECT /*+ MAPJOIN(smallTable) */ smallTable.key, bigTable.value FROM smallTable JOIN bigTable ON smallTable.key
= bigTable.key;
/*+mapjoin(a,b,c)*/
/*+mapjoin(a)*/
3. Bucket Map Join
Bucket Map Join 是 Map Join 的升级版,适用于大表和大表的 Join 关联。
Bucket Map Join 的条件是要求参与 Join 的表都是分桶表,关联 key 为分桶字段,且其中一张表的分桶数量是另一张表分桶数量的整数倍,这是为了保证每个分桶都有对应的关联桶,避免奇数桶找不到对应关系。
条件满足后,便可以在两表的分桶间进行 Map Join,第二个 Map Job 无序再读取缓存小表,只需缓存分桶即可完成 Join。
4. Sort Merge Bucket Map Join ( SMB Map Join )
SMB Map Join 是基于 Bucket Map Join 的升级版,特点是速度快。
SMB Map Join 要求分桶内的数据是有序的,且分桶、排序、关联的字段 key 是相同的,并且满足其中一个表的桶是另一个表中桶的整数倍。
distribute by .... sort by ....
与 Bucket Map Join 算法不同的是,Bucket Map Join 实现算法原理仍然是 Hash Table,SMB Map Join 使用 Sort Merge Join 算法,该算法利用两个表桶中的key,顺序扫描完成 Join 关联。
由于不用制作 Hash Table,因此不需要缓存桶,所以 SMB Map Join 对内存没有要求,而 Bucket Map Join 仍然需要缓存表,对内存有一定要求。
常见参数:
## 当用户执行bucket map join的时候,发现不能执行时,禁止查询
set hive.enforce.sortmergebucketmapjoin=false;
## 如果join的表通过sort merge join的条件,join是否会自动转换为sort merge join
set hive.auto.convert.sortmerge.join=true;
## 当两个分桶表 join 时,如果 join on的是分桶字段,小表的分桶数是大表的倍数时,可以启用 mapjoin 来提高效率。
# bucket map join优化,默认值是 false
set hive.optimize.bucketmapjoin=false;
## bucket map join 优化,默认值是 false
set hive.optimize.bucketmapjoin.sortedmerge=false;