一、场景
MapJoin是Hive的一种优化操作,其适用于小表JOIN大表的场景,由于表的JOIN操作是在Map端且在内存进行的,所以其并不需要启动Reduce任务也就不需要经过shuffle阶段,从而能在一定程度上节省资源提高JOIN效率。
二、使用
2.1 Hive v0.7 之前通过在查询语句中增加一个标记进行触发:
SELECT /*+ MAPJOIN(smalltable)*/ smalltable.key,smalltable.value
FROM smalltable JOIN bigtable ON smalltable.key = bigtable.key
2.2 从Hive v0.7版本开始,废弃了2.1中的方式,但是如果增加了这个标记同样是有效的,如果不加这个标记,需要设置
set hive.auto.convert.JOIN=true;
这样hive才会在必要的时候启动这个优化,该参数默认情况下为fasle。我们也可以配置能够使用这个优化的小表的大小,参数(单位是字节,默认25M):
set hive.mapjoin.smalltable.filesize=25000000;
注意:
使用默认启动该优化的方式如果出现默名奇妙的BUG(比如MAPJOIN并不起作用),就将以下两个属性置为fase手动使用
MAPJOIN标记来启动该优化
set hive.auto.convert.join=false(关闭自动MAPJOIN转换操作)
set hive.ignore.mapjoin.hint=false(不忽略MAPJOIN标记)
2.3 Mapjoin还有一个比较重要的用处就是支持不等连接的join操作
如果将不等条件放在where中,则join阶段通常是通过on 1=1 这种会产生笛卡尔积的方式,效率比较低,如果采用mapjoin的方式,则会在map的过程中完成不等值的join操作,例如:
set hive.auto.convert.join=true;
select smalltable.key,
smalltable.value
from smalltable
join bigtable on smalltable.value>bigtable.value;
2.4 Mapjoin其他参数
2.4.1 多Mapjoin合并
hive.auto.convert.join.noconditionaltask 是否将多个mapjoin合并为一个
hive.auto.convert.join.noconditionaltask.size : 多个mapjoin转换为1个时,所有小表的文件大小总和的最大值。
eg:
一个大表顺序关联3个小表a(10M), b(8M),c(12M),如果hive.auto.convert.join.noconditionaltask.size的值:
a. 小于18M,则无法合并mapjoin,必须执行3个mapjoin;
b. 大于18M小于30M,则可以合并a和b表的mapjoin,所以只需要执行2个mapjoin;
c. 大于30M,则可以将3个mapjoin都合并为1个。
合并mapjoin的好处:
因为每个mapjoin都要执行一次map,需要读写一次大表的数据,所以多个mapjoin就要做多次的数据读写,合并mapjoin后只用读写一次,自然能大大加快速度。但是执行map是内存大小是有限制的,在一次map里对多个小表做mapjoin就必须把多个小表都加入内存,为了防止内存溢出,所以加了hive.auto.convert.join.noconditionaltask.size参数来做限制。不过,这个值只是限制输入的表文件的大小,并不代表实际mapjoin时hashtable的大小。
2.4.2 LocalTask内存使用率
hive.mapjoin.localtask.max.memory.usage 将小表转成hashtable的本地任务的最大内存使用率,默认0.9默认值是0.9
在mapjoin任务执行前,会创建一个新的本地的MapReduce任务,这个新任务负责将小表数据从 HDFS 上读取到内存中的哈希表中。读完后,将内存中的哈希表序列化为哈希表文件。在下一阶段,当 MapReduce 任务启动时,会将这个哈希表文件上传到 Hadoop 分布式缓存中,该缓存会将这些文件发送到每个 Mapper 的本地磁盘上。
在这个过程中,查询处理器在一个子的jvm里运行这个本地MapReduction任务,jvm堆大小跟Mapper的堆大小一样。本地MR可能内存消耗殆尽,查询处理器精确的计算本地MR的内存大小,一旦内存超过了设定的值,那么这个MR就会自动kill掉。可以通过设置上面这个参数尽可能多的使用Map的堆内存。
2.4.3 其他
hive.mapjoin.followby.gby.localtask.max.memory.usage : 如果mapjoin后面紧跟着一个group by任务,这种情况下 本地任务的最大内存使用率,默认是0.55。
hive.mapjoin.check.memory.rows : localtask每处理完多少行,就执行内存检查。默认为100000
如果我们的localtask的内存使用超过阀值,任务会直接失败。
三、说明
Mapjoin不支持右外连接(right outer join)和全外连接(full outer join),支持内连接(inner join)和左外连接(left outer join)