1、Join算法概述

  Hive拥有多种join算法,包括Common Join,Map Join,Bucket Map Join,Sort Merge Buckt Map Join等,下面对每种join算法做简要说明:
1)Common Join
  Common Join是Hive中最稳定的join算法,其通过一个MapReduce Job完成一个join操作。Map端负责读取join操作所需表的数据,并按照关联字段进行分区,通过Shuffle,将其发送到Reduce端,相同key的数据在Reduce端完成最终的Join操作。如下图所示:

  需要注意的是,sql语句中的join操作和执行计划中的Common Join任务并非一对一的关系,一个sql语句中的相邻的且关联字段相同的多个join操作可以合并为一个Common Join任务。
例如:

hive (default)>
select a.val, b.val, c.val
from a
join b on (a.key = b.key1)
join c on (c.key = b.key1)

  上述sql语句中两个join操作的关联字段均为b表的key1字段,则该语句中的两个join操作可由一个Common Join任务实现,也就是可通过一个Map Reduce任务实现。

hive (default)>
select a.val, b.val, c.val
from a
join b on (a.key = b.key1)
join c on (c.key = b.key2)

  上述sql语句中的两个join操作关联字段各不相同,则该语句的两个join操作需要各自通过一个Common Join任务实现,也就是通过两个Map Reduce任务实现。
2)Map Join
  Map Join算法可以通过两个只有map阶段的Job完成一个join操作。其适用场景为大表join小表。若某join操作满足要求,则第一个Job会读取小表数据,将其制作为hash table,并上传至Hadoop分布式缓存(本质上是上传至每个执行任务的NodeManager节点本地磁盘)。第二个Job会先从分布式缓存中读取小表数据,并缓存在Map Task的内存中,然后扫描大表数据,这样在map端即可完成关联操作。如下图所示:

3)Bucket Map Join
  Bucket Map Join是对Map Join算法的改进,其打破了Map Join只适用于大表join小表的限制,可用于大表join大表的场景。
  Bucket Map Join的核心思想是:若能保证参与join的表均为分桶表,且关联字段为分桶字段,且其中一张表的分桶数量是另外一张表分桶数量的整数倍,就能保证参与join的两张表的分桶之间具有明确的关联关系,所以就可以在两表的分桶间进行Map Join操作了。这样一来,第二个Job的Map端就无需再缓存小表的全表数据了,而只需缓存其所需的分桶即可。其原理如图所示:

4)Sort Merge Bucket Map Join
  Sort Merge Bucket Map Join(简称SMB Map Join)基于Bucket Map Join。SMB Map Join要求,参与join的表均为分桶表,且需保证分桶内的数据是有序的,且分桶字段、排序字段和关联字段为相同字段,且其中一张表的分桶数量是另外一张表分桶数量的整数倍。
  SMB Map Join同Bucket Join一样,同样是利用两表各分桶之间的关联关系,在分桶之间进行join操作,不同的是,分桶之间的join操作的实现原理。Bucket Map Join,两个分桶之间的join实现原理为Hash Join算法;而SMB Map Join,两个分桶之间的join实现原理为Sort Merge Join算法。
Hash Join和Sort Merge Join均为关系型数据库中常见的Join实现算法。Hash Join的原理相对简单,就是对参与join的一张表构建hash table,然后扫描另外一张表,然后进行逐行匹配。Sort Merge Join需要在两张按照关联字段排好序的表中进行,其原理如图所示:

  Hive中的SMB Map Join就是对两个分桶的数据按照上述思路进行Join操作。可以看出,SMB Map Join与Bucket Map Join相比,在进行Join操作时,Map端是无需对整个Bucket构建hash table,也无需在Map端缓存整个Bucket数据的,每个Mapper只需按顺序逐个key读取两个分桶的数据进行join即可。

2 、Map Join

  Map Join有两种触发方式,一种是用户在SQL语句中增加hint提示,另外一种是Hive优化器根据参与join表的数据量大小,自动触发。
1)Hint提示
  用户可通过如下方式,指定通过map join算法,并且ta将作为map join中的小表。这种方式已经过时,不推荐使用。

hive (default)>
select /*+ mapjoin(ta) */ta.id,tb.id
from table_a ta
join table_b tb
on ta.id=tb.id;

2)自动触发
  Hive在编译SQL语句阶段,起初所有的join操作均采用Common Join算法实现。
  之后在物理优化阶段,Hive会根据每个Common Join任务所需表的大小判断该Common Join任务是否能够转换为Map Join任务,若满足要求,便将Common Join任务自动转换为Map Join任务。
  但有些Common Join任务所需的表大小,在SQL的编译阶段是未知的(例如对子查询进行join操作),所以这种Common Join任务是否能转换成Map Join任务在编译阶是无法确定的。
  针对这种情况,Hive会在编译阶段生成一个条件任务(Conditional Task),其下会包含一个计划列表,计划列表中包含转换后的Map Join任务以及原有的Common Join任务。最终具体采用哪个计划,是在运行时决定的。
  Map join自动转换的主要涉及到的参数如下:

-- 启动Map Join自动转换
set hive.auto.convert.join=true;

  一个Common Join operator转为Map Join operator的判断条件,若该Common Join相关的表中,存在n-1张表的大小总和<=该值,则生成一个Map Join计划,此时可能存在多种n-1张表的组合均满足该条件,则hive会为每种满足条件的组合均生成一个Map Join计划,同时还会保留原有的Common Join计划作为后备(back up)计划,实际运行时,优先执行Map Join计划,若不能执行成功,则启动Common Join后备计划。

set hive.mapjoin.smalltable.filesize=250000;
--开启无条件转Map Join
set hive.auto.convert.join.noconditionaltask=true;
--无条件转Map Join时的小表之和阈值,若一个Common Join operator相关的表中,存在n-1张表的大小总和<=该值,此时hive便不会再为每种n-1张表的组合均生成Map Join计划,同时也不会保留Common Join作为后备计划。而是只生成一个最优的Map Join计划。
set hive.auto.convert.join.noconditionaltask.size=10000000;

2.1 优化案例

1)示例SQL

hive (default)>
select*
from order_detail od
join product_info product on od.product_id = product.id
join province_info province on od.province_id = province.id;

2)优化前
  上述SQL语句共有三张表进行两次join操作,且两次join操作的关联字段不同。故优化前的执行计划应该包含两个Common Join operator,也就是由两个MapReduce任务实现。
3)优化思路
  经分析,参与join的三张表,数据量如下

表名 大小
order_detail 1176009934(约1122M)
product_info 25285707(约24M)
province_info 369(约0.36K)

注:可使用如下语句获取表/分区的大小信息

hive (default)>
desc formatted table_name partition(partition_col='partition');

  三张表中,product_info和province_info数据量较小,可考虑将其作为小表,进行Map Join优化。
  根据前文Common Join operator转Map Join operator的判断逻辑图,可得出以下优化方案:
方案一:
启用Map Join自动转换。

hive (default)>
set hive.auto.convert.join=true;

不使用无条件转Map Join。

hive (default)>
set hive.auto.convert.join.noconditionaltask=false;

调整hive.mapjoin.smalltable.filesize参数,使其大于等于product_info。

hive (default)>
set hive.mapjoin.smalltable.filesize=25285707;

  这样可保证将两个Common Join operator均可转为Map Join operator,并保留Common Join作为后备计划,保证计算任务的稳定。

方案二:
启用Map Join自动转换。

hive (default)>
set hive.auto.convert.join=true;

使用无条件转Map Join。

hive (default)>
set hive.auto.convert.join.noconditionaltask=true;

调整hive.auto.convert.join.noconditionaltask.size参数,使其大于等于product_info和province_info之和。

hive (default)>
set hive.auto.convert.join.noconditionaltask.size=25286076;

  这样可直接将两个Common Join operator转为两个Map Join operator,并且由于两个Map Join operator的小表大小之和小于等hive.auto.convert.join.noconditionaltask.size,故两个Map Join operator任务可合并为同一个。这个方案计算效率最高,但需要的内存也是最多的。
方案三:
启用Map Join自动转换。

hive (default)>
set hive.auto.convert.join=true;

使用无条件转Map Join。

hive (default)>
set hive.auto.convert.join.noconditionaltask=true;

调整hive.auto.convert.join.noconditionaltask.size参数,使其等于product_info。

hive (default)>
set hive.auto.convert.join.noconditionaltask.size=25285707;

这样可直接将两个Common Join operator转为Map Join operator,但不会将两个Map Join的任务合并。该方案计算效率比方案二低,但需要的内存也更少。

3、 Bucket Map Join

  Bucket Map Join不支持自动转换,发须通过用户在SQL语句中提供如下Hint提示,并配置如下相关参数,方可使用。
1)Hint提示

hive (default)>
select /*+ mapjoin(ta) */ta.id,tb.id
from table_a ta
join table_b tb on ta.id=tb.id;

2)相关参数

--关闭cbo优化,cbo会导致hint信息被忽略
set hive.cbo.enable=false;
--map join hint默认会被忽略(因为已经过时),需将如下参数设置为true
set hive.ignore.mapjoin.hint=false;
--启用bucket map join优化功能
set hive.optimize.bucketmapjoin = true;

3.1 优化案例
1)示例SQL

hive (default)>
select*
from(select*from order_detailwhere dt='2020-06-14'
)od
join(select*from payment_detailwhere dt='2020-06-14'
)pd
on od.id=pd.order_detail_id;

2)优化前
  上述SQL语句共有两张表一次join操作,故优化前的执行计划应包含一个Common Join任务,通过一个MapReduce Job实现。
3)优化思路
经分析,参与join的两张表,数据量如下。

表名 大小
order_detail 1176009934(约1122M)
payment_detail 334198480(约319M)

  两张表都相对较大,若采用普通的Map Join算法,则Map端需要较多的内存来缓存数据,当然可以选择为Map段分配更多的内存,来保证任务运行成功。但是,Map端的内存不可能无上限的分配,所以当参与Join的表数据量均过大时,就可以考虑采用Bucket Map Join算法。
  如何使用Bucket Map Join:首先需要依据源表创建两个分桶表,order_detail建议分16个bucket,payment_detail建议分8个bucket,注意分桶个数的倍数关系以及分桶字段。
订单表

hive (default)>
drop table if exists order_detail_bucketed;
create table order_detail_bucketed(id           string comment '订单id',user_id      string comment '用户id',product_id   string comment '商品id',province_id  string comment '省份id',create_time  string comment '下单时间',product_num  int comment '商品件数',total_amount decimal(16, 2) comment '下单金额'
)
clustered by (id) into 16 buckets
row format delimited fields terminated by '\t';

支付表

hive (default)>
drop table if exists payment_detail_bucketed;
create table payment_detail_bucketed(id              string comment '支付id',order_detail_id string comment '订单明细id',user_id         string comment '用户id',payment_time    string comment '支付时间',total_amount    decimal(16, 2) comment '支付金额'
)
clustered by (order_detail_id) into 8 buckets
row format delimited fields terminated by '\t';

然后向两个分桶表导入数据。
订单表

hive (default)>
insert overwrite table order_detail_bucketed
selectid,user_id,product_id,province_id,create_time,product_num,total_amount
from order_detail
where dt='2020-06-14';

分桶表

hive (default)>
insert overwrite table payment_detail_bucketed
selectid,order_detail_id,user_id,payment_time,total_amount
from payment_detail
where dt='2020-06-14';

然后设置以下参数:

--关闭cbo优化,cbo会导致hint信息被忽略,需将如下参数修改为false
set hive.cbo.enable=false;
--map join hint默认会被忽略(因为已经过时),需将如下参数修改为false
set hive.ignore.mapjoin.hint=false;
--启用bucket map join优化功能,默认不启用,需将如下参数修改为true
set hive.optimize.bucketmapjoin = true;

最后在重写SQL语句,如下:

hive (default)>
select /*+ mapjoin(pd) */*
from order_detail_bucketed od
join payment_detail_bucketed pd on od.id = pd.order_detail_id;

  需要注意的是,Bucket Map Join的执行计划的基本信息和普通的Map Join无异,若想看到差异,可执行如下语句,查看执行计划的详细信息。详细执行计划中,如在Map Join Operator中看到 “BucketMapJoin: true”,则表明使用的Join算法为Bucket Map Join。

hive (default)>
explain extended select /*+ mapjoin(pd) */*
from order_detail_bucketed od
join payment_detail_bucketed pd on od.id = pd.order_detail_id;

4、 Sort Merge Bucket Map Join

  Sort Merge Bucket Map Join有两种触发方式,包括Hint提示和自动转换。Hint提示已过时,不推荐使用。下面是自动转换的相关参数:

--启动Sort Merge Bucket Map Join优化
set hive.optimize.bucketmapjoin.sortedmerge=true;
--使用自动转换SMB Join
set hive.auto.convert.sortmerge.join=true;

4.1 优化案例
1)示例SQL语句

hive (default)>
select*
from(select*from order_detailwhere dt='2020-06-14'
)od
join(select*from payment_detailwhere dt='2020-06-14'
)pd
on od.id=pd.order_detail_id;

2)优化前
  上述SQL语句共有两张表一次join操作,故优化前的执行计划应包含一个Common Join任务,通过一个MapReduce Job实现。
3)优化思路
  经分析,参与join的两张表,数据量如下:

表名 大小
order_detail 1176009934(约1122M)
payment_detail 334198480(约319M)

  两张表都相对较大,除了可以考虑采用Bucket Map Join算法,还可以考虑SMB Join。相较于Bucket Map Join,SMB Map Join对分桶大小是没有要求的。
  如何使用SMB Map Join:首先需要依据源表创建两个的有序的分桶表,order_detail建议分16个bucket,payment_detail建议分8个bucket,注意分桶个数的倍数关系以及分桶字段和排序字段。
订单表

hive (default)>
drop table if exists order_detail_sorted_bucketed;
create table order_detail_sorted_bucketed(id           string comment '订单id',user_id      string comment '用户id',product_id   string comment '商品id',province_id  string comment '省份id',create_time  string comment '下单时间',product_num  int comment '商品件数',total_amount decimal(16, 2) comment '下单金额'
)
clustered by (id) sorted by(id) into 16 buckets
row format delimited fields terminated by '\t';

支付表

hive (default)>
drop table if exists payment_detail_sorted_bucketed;
create table payment_detail_sorted_bucketed(id              string comment '支付id',order_detail_id string comment '订单明细id',user_id         string comment '用户id',payment_time    string comment '支付时间',total_amount    decimal(16, 2) comment '支付金额'
)
clustered by (order_detail_id) sorted by(order_detail_id) into 8 buckets
row format delimited fields terminated by '\t';

然后向两个分桶表导入数据。
订单表

hive (default)>
insert overwrite table order_detail_sorted_bucketed
selectid,user_id,product_id,province_id,create_time,product_num,total_amount
from order_detail
where dt='2020-06-14';

分桶表

hive (default)>
insert overwrite table payment_detail_sorted_bucketed
selectid,order_detail_id,user_id,payment_time,total_amount
from payment_detail
where dt='2020-06-14';

然后设置以下参数:

--启动Sort Merge Bucket Map Join优化
set hive.optimize.bucketmapjoin.sortedmerge=true;
--使用自动转换SMB Join
set hive.auto.convert.sortmerge.join=true;

最后在重写SQL语句,如下:

hive (default)>
select*
from order_detail_sorted_bucketed od
join payment_detail_sorted_bucketed pd
on od.id = pd.order_detail_id;

Hive优化之Join(三)相关推荐

  1. 大数据开发实战:Hive优化实战2-大表join小表优化

    4.大表join小表优化 和join相关的优化主要分为mapjoin可以解决的优化(即大表join小表)和mapjoin无法解决的优化(即大表join大表),前者相对容易解决,后者较难,比较麻烦. 首 ...

  2. hive 行转列和列转行的方法_读离线和实时大数据开发实战,为你揭开 Hive 优化实践的神秘面纱...

    前言 「1024,1GB,一级棒!程序仔们节日快乐!」 ❝ 指尖流动的 1024 行代码,到底是什么? ❞ ❝ 是10行的迷茫?是101行的叛逆?是202行的理性思考?是307行对渴望的冲动?还是40 ...

  3. 深入浅出学Hive:Hive优化

    目录: 初始Hive Hive安装与配置 Hive内建操作符与函数开发 Hive JDBC Hive参数 Hive高级编程 Hive QL Hive Shell基本操作 Hive优化 Hive体系结构 ...

  4. hive 优化(二)

    在讨论hive优化之前,我们需要知道的是HQL它的执行过程. 简单的说,HQL会最终转化为job,然后通过MR来执行job 问题一 既然HQL会转化为JOB,那么如果job数量太多,会不会对hive执 ...

  5. CC00027.hadoop——|HadoopHive.V27|——|Hive.v27|Hive优化策略|实战.v03|

    一.SQL优化 ### --- SQL优化~~~ 列裁剪和分区裁剪 ~~~ 列裁剪是在查询时只读取需要的列:分区裁剪就是只读取需要的分区. ~~~ 简单的说:select 中不要有多余的列,坚决避免 ...

  6. HIVE优化的四种方法

    1.Hive整体架构优化 2.在MR阶段进行优化 3.Hive在SQL中优化 4.Hive框架平台优化 1.hive整体架构优化: 现在hive的整体框架如下,计算引擎不仅仅支持Map/Reduce, ...

  7. 大数据笔记30—Hadoop基础篇13(Hive优化及数据倾斜)

    Hive优化及数据倾斜 知识点01:回顾 知识点02:目标 知识点03:Hive函数:多行转多列 知识点04:Hive函数:多行转单列 知识点05:Hive函数:多列转多行 知识点06:Hive函数: ...

  8. 轻松玩转hive中各种join之间的关系以及使用

    hive编程是整个数据仓库操作的核心,而各种业务之间的join是hive的核心,所以熟练明白滴掌握hive中的各种join是数据仓库开发工程师必备的技能.    hive中的join只支持等值join ...

  9. [hive]hive优化

    1.fetch抓取 1)什么是fetch抓取 fetch抓取是指hive对select 所有字段.select 指定字段.limit可以不必使用MapReduce计算,在这种情况下,hive可以简单地 ...

最新文章

  1. 为什么我们都要等到失去后才知道珍惜呢(转载)
  2. ajax用https请求不了_Chrome滚动事件概率性Block Ajax请求
  3. oracle 12519,TNS-12519 与 processes 参数设置
  4. 如何避免订单重复支付?
  5. 高可用集群heartbeat安装配置(一)
  6. 解决:-bash: telnet: command not found
  7. 2017.4.16 幂次方 思考记录
  8. android升级adt和sdk之后无法识别SDK Location的一个解决方式
  9. maven00----maven学习说明
  10. SAP License:SAP自学SAP常见的问题二
  11. Android如何使用WebView访问https的网站
  12. 统计学原理 实验方法
  13. 十五分钟了解朱利亚集
  14. 笔记︱横截面回归模型中调节效应+中介效应(横截面回归模型两大方向)
  15. 金蝶中间件中标国家金质工程
  16. python打印N*N乘法表
  17. 大学MOOC现代礼仪试题用哪个搜题软件好?里面的题库难吗?
  18. SQL14 从titles表获取按照title进行分组,注意对于重复的emp_no进行忽略。
  19. 油漆算法问题_不同类型的油漆(以及何时使用它们)
  20. C语言中指针*p、p以及p之间的区别以及*p和**p的区别

热门文章

  1. Vue——图片轮播组件
  2. 360度了解Stratifyd:AI驱动的增强智能数据分析平台
  3. C#激爽特性——扩展方法
  4. Java(HTML01)
  5. java反射机制的原理
  6. java传值给js 换行_JavaScript用document.write()输出换行的示例代码
  7. Android长连接心跳机制
  8. python基础 -文件和异常
  9. PPLive证实4月底获视频牌照
  10. 四十七.c语言数组作为函数参数