MapJoin是Hive里一个相当实用的优化手段,核心思路很简单——在Map阶段就把JOIN搞定,省掉中间那堆shuffle和传输的麻烦,查询速度自然就提上来了。下面几种方法,算是实践中比较管用的几条路。

先说最直接的:用/*+ MAPJOIN(table) */提示强制走MapJoin。比如大表和小表JOIN,把小的那个表塞进内存,Map阶段直接完成匹配。示例写法像这样:
SELECT /*+ MAPJOIN(small_table) */ t1.key, t1.value, t2.value
FROM large_table t1
JOIN small_table t2 ON t1.key = t2.key;
这里small_table会被加载到内存,Map阶段直接和large_table做关联,效率比走Reduce Join高出一截。
其次是数据类型的选择。连接的列最好类型一致或者至少兼容,不然隐式类型转换会白耗资源,得不偿失。
再来是对小表做分区。如果小表里数据量还是不小,可以按业务维度分区,查询时只加载命中分区的数据,内存占用更可控。建个分区表就行:
CREATE TABLE small_table (key INT, value STRING) PARTITIONED BY (partition_column INT);
还有一招是对两表都做桶(Bucketing)。相当于把数据预先分成固定数量的桶,Map阶段只需要处理相关的桶,减少数据扫描量。大表建桶的示例:
CREATE TABLE large_table (key INT, value STRING) PARTITIONED BY (partition_column INT) BUCKETS 10;
查询时配合MAPJOIN提示和分区过滤,效果更稳:
SELECT /*+ MAPJOIN(small_table) */ t1.key, t1.value, t2.value
FROM large_table t1
JOIN small_table t2 ON t1.key = t2.key
WHERE t1.partition_column = 0;
最后别忘了调整MapJoin的阈值。Hive默认的hive.auto.convert.join是自动转换的开关,但判断逻辑不一定贴合你的场景。可以手动调小hive.auto.convert.join.min.size,让小表更易被选为MapJoin对象:
SET hive.auto.convert.join=true;
SET hive.auto.convert.join.min.size=100000;
需要提醒的是,这些优化本质上是在用内存换性能。如果小表太大硬塞进内存,反而可能引发OOM。集群资源情况自己要心里有数,别一把反赌。把握好这个度,MapJoin才能真的把效率提起来。
