Hive常见调优技巧

文章目录

  • 减少数据量
  • 并行化执行
  • 开启动态分区
  • 开启JVM重用
  • 防止数据倾斜
    • Group by引起的数据倾斜
    • Join引起的数据倾斜
      • Skew join
      • 重写业务逻辑
  • MapJoin
    • 自动判断
    • 手动设置
  • map阶段优化
  • reduce阶段优化
    • 方法1
    • 方法2
  • 合并小文件

减少数据量

第一原则先降数据量再join

并行化执行

set hive.exec.parallel=true;
set hive.exec.parallel.thread.number=8;
hive默认job是顺序进行的,一个HQL拆分成多个job,job之间无依赖关系也没有相互影响可以并行执行
对于同一个sql来说同时可以运行的job的最大值,该参数默认为8.此时最大可以同时运行8个job

开启动态分区

set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict
启动动态分区功能

开启JVM重用

set mapred.job.reuse.jvm.num.tasks=10;
jvm的启动过程可能会造成相当大的开销,对于单个执行任务时间较短时候,频繁开启JVM将是很大的开销,开启JVM重用将会一直占用使用到的task插槽,以便进行重用,直到任务完成后才能释放。

防止数据倾斜

一般分为join引起和group by引起分别解决。

操作 原因 现象
Group by 分组key集中 处理某key值的reduce非常耗时
Join 关联key集中(例如关联字段空值过多) 处理某key值的reduce非常耗时

Group by引起的数据倾斜

分两方面优化:
第一个:
set hive.map.aggr=true;
set hive.groupby.mapaggr.checkinterval=100000;
set hive.map.aggr.hash.min.reduction=0.5;
hive.map.aggr=true(默认)参数控制在group by的时候是否map局部聚合,但也不是都会局部聚合,如果聚合前后差别不是很大,聚合也就没什么意义了。
后两个设置是判断是否需要做map局部聚合,即:预先取100000条数据聚合,如果聚合后的条数/100000>0.5,则不再聚合。

第二个:
set Hive.groupby.skewindata=true;
控制启动两个MR Job完成,第一个Job先不按GroupBy字段分发,而是随机分发做一次聚合,然后启动第二个Job,拿前面聚合过的数据按GroupBy字段分发计算出最终结果。但是否生效还存在限制,详情见 Hive-hive.groupby.skewindata配置相关问题调研

Join引起的数据倾斜

优化主要分两个方向:skew join和重写业务逻辑

Skew join

set hive.optimize.skewjoin=true;
set hive.skewjoin.key=100000;
记录超过hive.skewjoin.key(默认100000)阈值的key值先写入hdfs,然后再进行一个map join的job任务,最终和其他key值的结果合并为最终结果。

重写业务逻辑

这个需要结合具体的场景重写,例如:在日志表与用户表关联时候(通过user_id关联),直接关联可能导致user_id为null的发生数据倾斜,此时可以把日志表中user_id为null的单独处理,如下:

SELECT a.xx, b.yy FROM log a JOIN users b 
            ON a.user_id IS NOT NULL 
                AND a.user_id = b.user_id 
UNION ALL 
SELECT a.xx, NULL AS yy FROM log a WHERE a.user_id IS NULL;

MapJoin

自动判断

set.hive.auto.convert.join=true;
默认值是25mb,小表小于25mb自动启动mapjoin

手动设置

select /*+mapjoin(A)*/ f.a,f.b from A t join B f on (f.a=t.a)
其中,A为小表,将A表复制到所有节点

map阶段优化

通过调整max可以起到调整map数的作用,减小max可以增加map数,增大max可以减少map数。
需要提醒的是,直接调整mapred.map.tasks这个参数是没有效果的。
mapred.min.split.size: 指的是数据的最小分割单元大小;min的默认值是1B
mapred.max.split.size: 指的是数据的最大分割单元大小;max的默认值是256MB

reduce阶段优化

reduce个数的设定极大影响任务执行效率,不指定reduce个数的情况下,Hive会猜测确定一个reduce个数,基于以下两个设定:
hive.exec.reducers.bytes.per.reducer(每个reduce任务处理的数据量,默认为1000^3=1G)
hive.exec.reducers.max(每个任务最大的reduce数,默认为999)
计算reducer数的公式很简单N=min(参数2,总输入数据量/参数1)
调节的办法

方法1

set hive.exec.reducers.bytes.per.reducer=500000000;
调整hive.exec.reducers.bytes.per.reducer参数的值;

方法2

set mapred.reduce.tasks=15;
调整mapred.reduce.tasks参数的值;

合并小文件

设置map输入的小文件合并

set mapred.max.split.size=256000000;  
//一个节点上split的至少的大小(这个值决定了多个DataNode上的文件是否需要合并)
set mapred.min.split.size.per.node=100000000;
//一个交换机下split的至少的大小(这个值决定了多个交换机上的文件是否需要合并)  
set mapred.min.split.size.per.rack=100000000;
//执行Map前进行小文件合并
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; 

设置map输出和reduce输出进行合并的相关参数

//设置map端输出进行合并,默认为true
set hive.merge.mapfiles = true
//设置reduce端输出进行合并,默认为false
set hive.merge.mapredfiles = true
//设置合并文件的大小
set hive.merge.size.per.task = 256*1000*1000
//当输出文件的平均大小小于该值时,启动一个独立的MapReduce任务进行文件merge。
set hive.merge.smallfiles.avgsize=16000000

你可能感兴趣的:(大数据:hive,大数据)