1. 表的连接顺序
select a.xx,b.xx from table a join table b 和 select a.xx,b.xx from table b join table a 效果是不一样的 。左边(前面)的表 是被缓存(buffer)在memory中,而右边(后面)的表是被streamed (官方说明:In every map/reduce stage of the join, the last table in the sequence is streamed through the reducers where as the others are buffered.)。因此小表被buffer可以减少reduce阶段 memory的开销.即 小表放到左边
当然我们也可以指定哪个表被streamed . 例如:
select /*+ STREAMTABLE(a) */ a.xx,b.xx from table a join table b on a.xx=b.xx .这样左边的表a会被streamed
2. join on的条件发生在 where 之前
sql1: SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key=b.key) WHERE a.ds='2009-07-07' AND b.ds='2009-07-07'
对于 sql1 ,会先过滤on 中的条件(a.key = b.key) ,然后再过滤where中的条件。试想 如果 a.key=b.key 不匹配的情况下 得到 b.val b.ds 等所有的关于b的将会是null,再执行where中的条件 b.ds='2009-07-07' 肯定是要被过滤的。居然如此我们为什么不把where中的条件访问on 条件中呢?这样可以提前过滤数据, 修改后如sql2:
sql2: SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key=b.key AND b.ds='2009-07-07' AND a.ds='2009-07-07')
3. map side join
map-side join 是一种特殊类型的join。如果join 有一个较小的表 ,这个小表可以加载到in-memory构成hash map,直接在map/reduce 过程中的map阶段完成join(官网:MAPJOINs are processed by loading the smaller table into an in-memory hash map and matching keys with the larger table as they are streamed through.)
明确指定 mapjoin : select /*+ MAPJOIN(b) */ a.xx ,b.xx from a join b on a.xx = b.xx
或者shell 设置 hive> set hive.auto.convert.join=true;
hive> set hive.auto.convert.join.noconditionaltask=true;
hive > set hive.auto.convert.join.noconditionaltask.size = 10000000; //该属性可以控制多大的表可以自动触发放到内层中,默认大小为(10M)
备注:1. 如果join 是 full join类型 就不能使用 map-side了,因为左右两个表都需要被streamed
4.sort-merge-bucket join 转化为cmb map join
如果参与join的表是按照join 列分的桶,并且一个表分桶的个数是一个表分桶个数的整数倍,那么就可以根据桶进行join. e.g : select /* + MAPJOIN(b) */ a.key,a.value from a join b on a.key=b.key . 对于A中每个mapper,并不需要获取所有B中的数据,仅仅对应的桶中的数据是可以fetch 配置的(需要设置参数 set hive.optimize.bucketmapjoin = true)
进一步来说,如果参与join的表除了按照join列分的桶,并且还是排序的 , 一个 sort-merge join 可以是被执行的,下面的参数需要是被设置的(set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;
set hive.optimize.bucketmapjoin = true;
set hive.optimize.bucketmapjoin.sortedmerge = true;)
5. join 是从左向右关联的
sql : select a.xx , b.xx , c.xx from a join b on (a.xx= b.xx) left join c on (a.xx = c.xx)
执行过程是先 a 和 b 进行join ,生成的结果 在和 c进行 left join 。如果 表 a 、b、c中关联(on)条件 仅仅用到一个字段,将生成一个map-reduce 任务
例如:
SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1) 仅仅一个map-reduce任务
SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2) 生成2个map-reduce 任务
6.问题: map side 将小表 加载到 in-memory构成hash map 和 1中指出的将左边的表缓存(buffer)到in-memory 有什么不同呢? 或者说 hash map 到底是什么结构 buffer 存储的到底是什么呢?
参考链接: https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Joins
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+JoinOptimization