今天实验了一下hive中的mapjoin和bucket mapjoin,情况如下:
首先创建数据表和制造数据,表test1,仅包含1列(id int):
1. 创建表, 并以id字段划分桶, 桶个数为20个,也就是在插入数据时会生成20个数据文件对应20个桶
create table test_mapjoin(id int) clustered by (id) into 20 buckets;
2.导入数据前设置桶划分参数为真:sethive.enforce.bucketing=true,能够保证hive在插入数据时使用桶对数据划分,以下将插入300万行数据:
set hive.enforce.bucketing=true
insert overwrite table test_mapjoin select * from ids limit 3000000;
桶划分是对字段id使用hash计算,相同hash值的分配到同一个桶,在使用bucket进行mapjoin时效率很高,内存占用很小.
其中的一行日志显示将由20个reduce生成20个桶文件, "Hadoop job information for Stage-2: number of mappers: 1; number of reducers: 20"
可以看到插入数据后的表test_mapjoin的hdfs目录包含20个文件,由20个reduce生成:
-rw-r--r-- 1 ljq supergroup 1194 2014-05-15 17:42 /user/hive/warehouse/test_mapjoin/000000_0
-rw-r--r-- 1 ljq supergroup 1194 2014-05-15 17:42 /user/hive/warehouse/test_mapjoin/000001_0
-rw-r--r-- 1 ljq supergroup 1194 2014-05-15 17:42 /user/hive/warehouse/test_mapjoin/000002_0
-rw-r--r-- 1 ljq supergroup 1194 2014-05-15 17:42 /user/hive/warehouse/test_mapjoin/000003_0
-rw-r--r-- 1 ljq supergroup 1194 2014-05-15 17:42 /user/hive/warehouse/test_mapjoin/000004_0
-rw-r--r-- 1 ljq supergroup 1194 2014-05-15 17:42 /user/hive/warehouse/test_mapjoin/000005_0
-rw-r--r-- 1 ljq supergroup 1194 2014-05-15 17:42 /user/hive/warehouse/test_mapjoin/000006_0
-rw-r--r-- 1 ljq supergroup 1194 2014-05-15 17:42 /user/hive/warehouse/test_mapjoin/000007_0
-rw-r--r-- 1 ljq supergroup 1194 2014-05-15 17:42 /user/hive/warehouse/test_mapjoin/000008_0
-rw-r--r-- 1 ljq supergroup 1194 2014-05-15 17:42 /user/hive/warehouse/test_mapjoin/000009_0
-rw-r--r-- 1 ljq supergroup 1195 2014-05-15 17:42 /user/hive/warehouse/test_mapjoin/000010_0
-rw-r--r-- 1 ljq supergroup 1195 2014-05-15 17:42 /user/hive/warehouse/test_mapjoin/000011_0
-rw-r--r-- 1 ljq supergroup 1195 2014-05-15 17:43 /user/hive/warehouse/test_mapjoin/000012_0
-rw-r--r-- 1 ljq supergroup 1195 2014-05-15 17:43 /user/hive/warehouse/test_mapjoin/000013_0
-rw-r--r-- 1 ljq supergroup 1195 2014-05-15 17:43 /user/hive/warehouse/test_mapjoin/000014_0
-rw-r--r-- 1 ljq supergroup 1195 2014-05-15 17:43 /user/hive/warehouse/test_mapjoin/000015_0
-rw-r--r-- 1 ljq supergroup 1195 2014-05-15 17:43 /user/hive/warehouse/test_mapjoin/000016_0
-rw-r--r-- 1 ljq supergroup 1195 2014-05-15 17:43 /user/hive/warehouse/test_mapjoin/000017_0
-rw-r--r-- 1 ljq supergroup 1195 2014-05-15 17:43 /user/hive/warehouse/test_mapjoin/000018_0
-rw-r--r-- 1 ljq supergroup 1195 2014-05-15 17:43 /user/hive/warehouse/test_mapjoin/000019_0
3. 先使用普通mapjoin即 hive.optimize.bucketmapjoin=false:
select /*+mapjoin(a)*/ count(*) from test_mapjoin a join test_mapjoin b on a.id = b.id;
运行25分钟后,jvm heap size 错误, 这个参数设置的是1G.
4. 使用 bucket mapjoin, 即设置hive.optimize.bucketmapjoin=true:
set hive.optimize.bucketmapjoin=true;
select /*+mapjoin(a)*/ count(*) from test_mapjoin a join test_mapjoin b on a.id = b.id;
再次运行时, 只用了5分钟就完成了.
可见mapjoin和使用bucket进行mapjoin区别很大,当map端join小表仍然不能全部放进内存时,对两个表在join的key上都做hash bucket, 之后可以用bucket mapjoin, 因为bucket划分数据后,相同hash值的key都放在了同一个bucket中, 在join时, 小表将会被复制到所有节点, map加载小表的bucket到内存hashtable, 与大表对应的bucket文件进行join.