Hive优化相关(数据倾斜、join优化,分组聚合优化)

一篇文章带你了解Hive SQL的优化,以及相关参数设置。请认真读下去,你会有极大的收获、感想以及共鸣。

分组聚合优化

优化思路为:map-side聚合。

所谓map-side聚合,就是在map端维护一个hash table,利用其完成分区内的部分聚合,然后将部分聚合的结果,发送至reduce端,完成最终的聚合。

map-side聚合能有效减少shuffle的数据量,提高分组聚合运算的效率。

相关参数配置如下:

# 启用map-side聚合
set hive.map.aggr=true;  # (默认开启)

# hash table占用map端内存的最大比例
set hive.map.aggr.hash.percentmemory=0.5;

# 用于检测源表是否适合map-side聚合的条数。
set hive.groupby.mapaggr.checkinterval=100000;

# map-side聚合所用的HashTable,占用map任务堆内存的最大比例,
# 若超出该值,则会对HashTable进行一次flush。
set hive.map.aggr.hash.force.flush.memory.threshold=0.9;

Join优化

Hive拥有多种join算法,包括common joinmap joinSort Merge Bucket Map Join

  • common join

Map端负责读取参与join的表的数据,并按照关联字段进行分区,将其发送到Reduce端,Reduce端完成最终的join操作。

  • map join

若大表和小表join,Map端就会缓存小表全部数据,然后扫描另外一张大表,在Map端完成关联操作。

对表的要求是:一大一小

相关参数配置如下:

# 启用 map join 自动转换
set hive.auto.convert.join = true;  # (默认为 true)
# 小表的阈值设置(默认 25M 以下认为是小表):
set hive.mapjoin.smalltable.filesize = 25000000;  

# common join 转map join 小表阈值
set hive.auto.convert.join.noconditionaltask.size = 10000000 
  • Sort Merge Bucket Map Join

解决的是:大表join大表

分桶表(分桶字段和桶数取模):Hive 的分桶采用对分桶字段的值进行哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶中。

SMB map join要求:1、参与join的表均为分桶表;2、关联字段为分桶字段;3、分桶字段是有序的;4、大表的分桶数量是小表分桶数量的整数倍(相等亦可)。

满足以上要求,就可以以桶为单位,为每个Map分配任务了,Map端就无需再缓存小表的全表数据了,而只需缓存其所需的分桶。

相关参数配置如下:

# 启动Sort Merge Bucket Map Join优化
set hive.optimize.bucketmapjoin.sortedmerge=true; # 默认fasle

# 使用自动转换 SMB Join 
set hive.auto.convert.sortmerge.join=true;  # 默认是true

缺点:准备工作比较麻烦,通用性不强,换张大表,需要再次分桶准备。

数据倾斜优化

数据倾斜问题通常是指参与计算的数据分布不均,即某个key或者某些key的数据量远超其他key,导致在shuffle阶段,大量相同key的数据被发往一个Reduce,进而导致该Reduce所需的时间远超其他Reduce,成为整个任务的瓶颈。

Hive中的数据倾斜常出现在分组聚合join操作的场景中,下面分别介绍在上述两种场景下的优化思路。

一、分组聚合导致数据倾斜

根据分组字段进行分区

  • F1:开启map-side聚合

解释见:"分组聚合优化"的介绍。

相关参数配置如下:

# 启用map-side聚合
set hive.map.aggr=true;  # (默认开启)

# hash table占用map端内存的最大比例
set hive.map.aggr.hash.percentmemory=0.5;

# 用于检测源表是否适合map-side聚合的条数。
set hive.groupby.mapaggr.checkinterval=100000; 

# map-side聚合所用的HashTable,占用map任务堆内存的最大比例,
# 若超出该值,则会对HashTable进行一次flush。
set hive.map.aggr.hash.force.flush.memory.threshold=0.9;
  • F2:启用skew group by优化

相关参数配置如下:

# 启用skew groupby优化
set hive.groupby.skewindata = true;   # (默认关闭)

当选项设定为 true,生成的查询计划会有两个 MR Job。

第一个 MR Job 中, Map 的输出结果会随机分布到 Reduce 中,每个 Reduce 做部分聚合操作,并输出结果,这样处理的结果是相同的 Group By Key 有可能被分发到不同的 Reduce 中,从而达到负载均衡的目的。

第二个 MR Job 再根据预处理的数据结果按照 Group By Key 分布到 Reduce 中(这个过程可以保证相同的 Group By Key 被分布到同一个 Reduce 中),最后完成最终的聚合操作。

二、join导致数据倾斜

根据连接字段进行分区

  • F1:使用 map join

详见:"Join优化"的介绍。

  • F2:启用 skew join 优化

类似于 skew group by 分两个job,两次Join。需要注意的是,skew join 只支持 Inner Join。

相关参数配置如下:

# 启用skew join优化
set hive.optimize.skewjoin = true;  # 默认是false
# 触发skew join的阈值,若某个key的行数超过该参数值,则触发
set hive.skewjoin.key = 100000;   # (10万行)

任务并行度优化

  • Map个数

Map端的并行度,也就是Map的个数。是由输入文件的切片数决定的。一般情况下,Map端的并行度无需手动调整。Map端的并行度相关参数如下:

# blocksize 公式
computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize))) = blocksize = 128M 

minSize = 1

maxSize = long的最大值

降低map数,增大minSize

增加map数,减小maxSize

相关参数配置如下:

# 可将多个小文件切片,合并为一个切片,进而由一个 map 任务处理 (默认)
set hive.input.format = org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;   

# 一个切片的最大值
set mapreduce.input.fileinputformat.split.maxsize = 256000000;
set mapreduce.input.fileinputformat.split.minsize = 1;
  • Reduce 个数

Reduce端的并行度,相对来说,更需要关注。默认情况下,Hive会根据Reduce端输入数据的大小,估算一个Reduce并行度。但是在某些情况下,其估计值不一定是最合适的,故需要人为调整其并行度。

相关参数配置如下:

# 指定Reduce端并行度,默认值为-1,表示用户未指定
set mapreduce.job.reduces;
# Reduce 端并行度最大值,默认1009
set hive.exec.reducers.max;  
# 单个Reduce Task计算的数据量,用于估算Reduce并行度,默认256M
set hive.exec.reducers.bytes.per.reducer; 

Reduce端并行度的确定逻辑为:

若指定参数mapreduce.job.reduces的值为一个非负整数,则Reduce并行度为指定值。

否则,Hive会自行估算Reduce并行度,估算逻辑是和单个Reduce Task计算的数据量以及Reduce 端并行度最大值的一个关系式。

  • Job的并行度

参数hive.exec.parallel可以控制一个sql中多个可并行执行的job的运行方式,当hive.exec.parallel为true的时候,同一个sql中可以并行执行的job会并发的执行;

而参数hive.exec.parallel.thread.number就是控制对于同一个sql来说同时可以运行的job的最大值,该参数默认为8.

set hive.exec.parallel=true;
set hive.exec.parallel.thread.number=8;

小文件合并优化

小文件合并优化,分为两个方面,分别是Map端输入的小文件合并,和Reduce端输出的小文件合并。

  • Map 端输入文件合并

合并Map端输入的小文件,是指将多个小文件划分到一个切片中,进而由一个Map Task去处理。目的是防止为单个小文件启动一个Map Task,浪费计算资源。

相关参数配置如下:

# 可将多个小文件切片,合并为一个切片,进而由一个 map 任务处理
set hive.input.format = org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;

# 在Map-only的任务结束时合并小文件
SET hive.merge.mapfiles = true;  # 默认true
  • Reduce 端输出文件合并

合并Reduce端输出的小文件,是指将多个小文件合并成大文件。目的是减少HDFS小文件数量。

相关参数配置如下:

# 开启合并 Hive on Spark 任务输出的小文件
set hive.merge.sparkfiles = true;           # 默认false

# 开启合并 Hive on MR 任务输出的小文件
set hive.merge.mapredfiles = true;          # 默认false

# 合并大小, 默认 256M
SET hive.merge.size.per.task = 268435456;
# 当输出文件的平均大小小于该值时,启动一个独立的 map-reduce 任务进行文件 merge
SET hive.merge.smallfiles.avgsize = 16000000;  # 默认 16M

太重要了太重要了,如果看着有难度的话,可以结合网络上的其他文章一起阅读理解。但是,一定要去理解呀,不能仅仅只是看一遍。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Li解Code

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值