分享

Hive的三种Join方式

 jasonbetter 2019-08-28

Hive中就是把Map,Reduce的Join拿过来,通过SQL来表示。
参考链接:https://cwiki./confluence/display/Hive/LanguageManual+Joins

Common/Shuffle/Reduce Join

Reduce Join在Hive中也叫Common Join或Shuffle Join
如果两边数据量都很大,它会进行把相同key的value合在一起,正好符合我们在sql中的join,然后再去组合,如图所示。

Reduce Join

Map Join

    1) 大小表连接:

  • 如果一张表的数据很大,另外一张表很少(<1000行),那么我们可以将数据量少的那张表放到内存里面,在map端做join。
    Hive支持Map Join,用法如下

  1. select /*+ MAPJOIN(time_dim) */ count(1) from

  2. store_sales join time_dim on (ss_sold_time_sk = t_time_sk)

    2) 需要做不等值join操作(a.x < b.y 或者 a.x like b.y等)

  • 这种操作如果直接使用join的话语法不支持不等于操作,hive语法解析会直接抛出错误
    如果把不等于写到where里会造成笛卡尔积,数据异常增大,速度会很慢。甚至会任务无法跑成功~
    根据mapjoin的计算原理,MapJoin会把小表全部读入内存中,在map阶段直接拿另外一个表的数据和内存中表数据做匹配。这种情况下即使笛卡尔积也不会对任务运行速度造成太大的效率影响。
    而且hive的where条件本身就是在map阶段进行的操作,所以在where里写入不等值比对的话,也不会造成额外负担。

  1. select /*+ MAPJOIN(a) */

  2. a.start_level, b.*

  3. from dim_level a

  4. join (select * from test) b

  5. where b.xx>=a.start_level and b.xx<end_level;

3) MAPJOIN 结合 UNIONALL
原始sql:

  1. select a.*,coalesce(c.categoryid,’NA’) as app_category

  2. from (select * from t_aa_pvid_ctr_hour_js_mes1

  3. ) a

  4. left outer join

  5. (select * fromt_qd_cmfu_book_info_mes

  6. ) c

  7. on a.app_id=c.book_id;

速度很慢,老办法,先查下数据分布:

  1. select *

  2. from

  3. (selectapp_id,count(1) cnt

  4. fromt_aa_pvid_ctr_hour_js_mes1

  5. group by app_id) t

  6. order by cnt DESC

  7. limit 50;

数据分布如下:

  1. NA 617370129

  2. 2 118293314

  3. 1 40673814

  4. d 20151236

  5. b 1846306

  6. s 1124246

  7. 5 675240

  8. 8 642231

  9. 6 611104

  10. t 596973

  11. 4 579473

  12. 3 489516

  13. 7 475999

  14. 9 373395

  15. 107580 10508

我们可以看到除了NA是有问题的异常值,还有appid=1~9的数据也很多,而这些数据是可以关联到的,所以这里不能简单的随机函数了。而t_qd_cmfu_book_info_mes这张app库表,又有几百万数据,太大以致不能放入内存使用mapjoin。

解决方:首先将appid=NA和1到9的数据存入一组,并使用mapjoin与维表(维表也限定appid=1~9,这样内存就放得下了)关联,而除此之外的数据存入另一组,使用普通的join,最后使用union all 放到一起。

  1. select a.*,coalesce(c.categoryid,’NA’) as app_category

  2. from --if app_id isnot number value or <=9,then not join

  3. (select * fromt_aa_pvid_ctr_hour_js_mes1

  4. where cast(app_id asint)>9

  5. ) a

  6. left outer join

  7. (select * fromt_qd_cmfu_book_info_mes

  8. where cast(book_id asint)>9) c

  9. on a.app_id=c.book_id

  10. union all

  11. select /*+ MAPJOIN(c)*/

  12. a.*,coalesce(c.categoryid,’NA’) as app_category

  13. fromif app_id<=9,use map join

  14. (select * fromt_aa_pvid_ctr_hour_js_mes1

  15. where coalesce(cast(app_id as int),-999)<=9) a

  16. left outer join

  17. (select * fromt_qd_cmfu_book_info_mes

  18. where cast(book_id asint)<=9) c

  19. --if app_id is notnumber value,then not join

  20. on a.app_id=c.book_id

    设置:

  • 当然也可以让hive自动识别,把join变成合适的Map Join如下所示
    注:当设置为true的时候,hive会自动获取两张表的数据,判定哪个是小表,然后放在内存中

  1. set hive.auto.convert.join=true;

  2. select count(*) from store_sales join time_dim on (ss_sold_time_sk = t_time_sk)

SMB(Sort-Merge-Buket) Join

    场景:

  • 大表对小表应该使用MapJoin,但是如果是大表对大表,如果进行shuffle,那就要人命了啊,第一个慢不用说,第二个容易出异常,既然是两个表进行join,肯定有相同的字段吧。

  • tb_a - 5亿(按排序分成五份,每份1亿放在指定的数值范围内,类似于分区表)
    a_id
    100001 ~ 110000 - bucket-01-a -1亿
    110001 ~ 120000
    120001 ~ 130000
    130001 ~ 140000
    140001 ~ 150000

  • tb_b - 5亿(同上,同一个桶只能和对应的桶内数据做join)
    b_id
    100001 ~ 110000 - bucket-01-b -1亿
    110001 ~ 120000
    120001 ~ 130000
    130001 ~ 140000
    140001 ~ 150000

  • 注:实际生产环境中,一天的数据可能有50G(举例子可以把数据弄大点,比如说10亿分成1000个bucket)。

  • 原理:

  • 在运行SMB Join的时候会重新创建两张表,当然这是在后台默认做的,不需要用户主动去创建,如下所示:

  • SMB Join

设置(默认是false):

  1. set hive.auto.convert.sortmerge.join=true

  2. set hive.optimize.bucketmapjoin=true;

  3. set hive.optimize.bucketmapjoin.sortedmerge=true;

    总结:

  • 其实在写程序的时候,我们就可以知道哪些是大表哪些是小表,注意调优。

  • 转自:http://www.cnblogs.com/raymoc/p/5323824.html

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多