
# Hive Join数据优化
#### 操作场景
使用Join语句时，如果数据量大，可能造成命令执行速度和查询速度慢，此时可进行Join优化。
Join优化可分为以下方式：
- Map Join
- Sort Merge Bucket Map Join
- Join顺序优化
 
#### Map Join
Hive的Map Join适用于能够在内存中存放下的小表（指表大小小于25MB），通过"hive.mapjoin.smalltable.filesize"定义小表的大小，默认为25MB。
Map Join需在执行语句前设置如下参数开启（当前版本中该值默认为"true"）：
**set hive.auto.convert.join=true;**
使用Map Join时没有Reduce任务，而是在Map任务前起了一个MapReduce Local Task，这个Task通过TableScan读取小表内容到本机，在本机以HashTable的形式保存并写入硬盘上传到DFS，并在distributed cache中保存，在Map Task中从本地磁盘或者distributed cache中读取小表内容直接与大表join得到结果并输出。
使用Map Join时需要注意小表不能过大，如果小表将内存基本用尽，会使整个系统性能下降甚至出现内存溢出的异常。
#### Sort Merge Bucket Map Join
使用Sort Merge Bucket Map Join必须满足以下2个条件：
- join的两张表都很大，内存中无法存放。
- 两张表都按照join key进行分桶（clustered by (column)）和排序（sorted by(column)），且两张表的分桶数正好是倍数关系。
通过如下设置，启用Sort Merge Bucket Map Join：
**set hive.optimize.bucketmapjoin=true;**
**set hive.optimize.bucketmapjoin.sortedmerge=true;**
这种Map Join也没有Reduce任务，是在Map任务前启动MapReduce Local Task，将小表内容按桶读取到本地，在本机保存多个桶的HashTable备份并写入HDFS，并保存在Distributed Cache中，在Map Task中从本地磁盘或者Distributed Cache中按桶一个一个读取小表内容，然后与大表做匹配直接得到结果并输出。
#### Join顺序优化
当有3张及以上的表进行Join时，选择不同的Join顺序，执行时间存在较大差异。使用恰当的Join顺序可以有效缩短任务执行时间。
Join顺序原则：
- Join出来结果较小的组合，例如表数据量小或两张表Join后产生结果较少，优先执行。
- Join出来结果大的组合，例如表数据量大或两张表Join后产生结果较多，在后面执行。
例如，customer表的数据量最多，orders表和lineitem表优先Join可获得较少的中间结果。
原有的Join语句如下：
```
select
  l_orderkey,
  sum(l_extendedprice * (1 - l_discount)) as revenue,
  o_orderdate,
  o_shippriority
from
  customer,
  orders,
  lineitem
where
  c_mktsegment = 'BUILDING'
  and c_custkey = o_custkey
  and l_orderkey = o_orderkey
  and o_orderdate < '1995-03-22'
  and l_shipdate > '1995-03-22'
limit 10;
```
Join顺序优化后如下：
```
select
  l_orderkey,
  sum(l_extendedprice * (1 - l_discount)) as revenue,
  o_orderdate,
  o_shippriority
from
  orders,
  lineitem,
  customer
where
  c_mktsegment = 'BUILDING'
  and c_custkey = o_custkey
  and l_orderkey = o_orderkey
  and o_orderdate < '1995-03-22'
  and l_shipdate > '1995-03-22'
limit 10;
```
#### 注意事项
**Join** **数据倾斜问题**
执行任务的时候，任务进度长时间维持在99%，这种现象叫数据倾斜。
数据倾斜是经常存在的，因为有少量的Reduce任务分配到的数据量和其他Reduce差异过大，导致大部分Reduce都已完成任务，但少量Reduce任务还没完成的情况。
解决数据倾斜的问题，可通过设置"set hive.optimize.skewjoin=true"并调整hive.skewjoin.key的大小。hive.skewjoin.key是指Reduce端接收到多少个key即认为数据是倾斜的，并自动分发到多个Reduce。
