Hive调优

Fetch抓取

  1. Fetch抓取是指能不走MapReduce任务就不走MapReduce任务
    eg:select * from A,在这种情况下,Hive可以直接读取A表的存储目录下的文件
  2. 参数设置
hive (qi)> set hive.fetch.task.conversion=more;

join优化

小表 join 大表

即数据量小的表放在 join 的左边,大表放在join的右边。这样可以 map join可以让小表先进内存,大表的数据从文件读取。(Hive已实现自动优化,自动判断小表)

  1. 设置选择 mapjoin
hive (qi)> set hive.auto.convert.join=true;
  1. 小表的阈值设置(默认25M以下是小表)
hive (qi)> set hive.mapjoin.smalltable.filesize;
hive.mapjoin.smalltable.filesize=25000000

大表 join 大表

null 值过滤 (join 会自动过滤,left/right join 不会自动过滤)
有时join 超时很可能是因为 key 对应的数据太多,相同的 key 对应的数据会发送到相同的 reducer上,导致内存不够

  1. null 值转换
    适用于 left/rigth join(非 inner join),这时,我们可以将左表为 null 的数据随机设置 (随机设置的值在右表中必须不存在!),这样数据就会随机均匀的分到不同的 reduce 上。
select n.* from A a full join B b on nvl(a.id,rand()) = b.id;

这样设置的话,A表中为 null 会被随机分配一个数字,但要保证这些随机分配的数据在 B 表不存在,这样 A 表中为 null 的字段才会被过滤掉。

  1. SMB(Sort Merge Bucket)join
    创建两个分桶表再进行join,这样可以在一个桶内发生笛卡尔积连接
set hive.optimize.bucketmapjoin = true; 
set hive.optimize.bucketmapjoin.sortedmerge = true; 
set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;

数据倾斜

有时会发现多个 reduce 任务中发现有1个或少量的 reduce 任务时间很长甚至未完成,这是因为某个 reduce 的数据量比其他 reducer 多的多。

  1. 在 map 端进行聚合,减少传给 reduce 的数据量
set hive.map.aggr = true
# 有数据倾斜时进行负载均衡
set hive.groupby.skewindata = true

开启负载均衡后,会生成两个 MRJob,第一个 MRJob,Map的输出结果会随机分配到 reduce 中,每个reduce 完成部分的聚合,并输出结果,这样相同的 GroupByKey 有可能分发到不同的 Reduce中。
第二个 MRJob 再根据预处理的数据结果按照 GroupByKey 分配到 Reduce 中,最后完成最终的聚合操作

  1. count distinct优化
    count distinct 只需要用一个 reduce task 完成,在数据量大的情况下,会导致这个 reduce 处理的数据量太大,从而导致 Job 难以完成
select count(name) from (select name from A group by name) a;
  1. 控制 null 值的分布
    可以提前过滤掉 null 值,或者将 null 值转换,使其随机分布

笛卡尔积

尽量避免笛卡尔积,join 时要加 on 条件,并且必须是有效的 on 条件

使用分区表分桶表

  1. 分区表可以将数据根据设定的分区分配到不同的文件夹中,查询时可以通过指定的分区进行读取
  2. 分桶表是将数据按指定列的 hash 散列后分在了不同的文件中,查询时,Hive 可以根据分桶结构,快速定位到数据所在的分桶文件

SQL方面的优化

where 条件优化

优化前:

select o.id from bigtable b join bigtable o on o.id = b.id where o.id <= 10;

优化后:

select b.id from bigtable b join (select id from bigtable where id <= 10) o on b.id = o.id;

union优化

  • union:去重
  • unionall:不去重
    优先考虑 unionall
    如果不存在去重的情况下,union 和 unionall 没有区别,应该使用 unionall

合并小文件

  1. map 执行前合并小文件,减少 map 数
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
  1. map 输出、reduce 输出时合并小文件
# 在 map 输出时合并小文件
SET hive.merge.mapfiles = true; 
# 在 map-reduce 任务结束时合并小文件,默认 false 
SET hive.merge.mapredfiles = true; 
# 合并文件的大小,默认 256M 
SET hive.merge.size.per.task = 268435456; 
# 当输出文件的平均大小小于该值时,启动一个独立的 map-reduce 任务进行文件 merge 
SET hive.merge.smallfiles.avgsize = 16777216;

合理设置 reduce 的数量

每个 Reduce 处理的数据量默认是 256MB 
set hive.exec.reducers.bytes.per.reducer=256000000 
每个任务最大的 reduce 数,默认为 1009 
set hive.exec.reducers.max=1009

计算 reducer 数的公式
N=min(参数2,总输入数据量/参数1)

开启JVM重用

JVM重用对hive的性能影响非常大,特别是对于难以避免的小文件场景或者task特别多的场景,这类场景大多数执行时间都很短,jvm启动过程可能会造成相当大的开销

set mapred.job.reuse.jvm.num.tasks=10;

并行执行

在系统资源比较空闲的时候,并行执行才有优势

set hive.exec.parallel=true;  
# 同一个sql允许最大并行度,默认为8
set hive.exec.parallel.thread.number=16;