Hive调优
Fetch抓取
- Fetch抓取是指能不走MapReduce任务就不走MapReduce任务
eg:select * from A,在这种情况下,Hive可以直接读取A表的存储目录下的文件 - 参数设置
hive (qi)> set hive.fetch.task.conversion=more;
join优化
小表 join 大表
即数据量小的表放在 join 的左边,大表放在join的右边。这样可以 map join可以让小表先进内存,大表的数据从文件读取。(Hive已实现自动优化,自动判断小表)
- 设置选择 mapjoin
hive (qi)> set hive.auto.convert.join=true;
- 小表的阈值设置(默认25M以下是小表)
hive (qi)> set hive.mapjoin.smalltable.filesize;
hive.mapjoin.smalltable.filesize=25000000
大表 join 大表
null 值过滤 (join 会自动过滤,left/right join 不会自动过滤)
有时join 超时很可能是因为 key 对应的数据太多,相同的 key 对应的数据会发送到相同的 reducer上,导致内存不够
- 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 的字段才会被过滤掉。
- 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 多的多。
- 在 map 端进行聚合,减少传给 reduce 的数据量
set hive.map.aggr = true
# 有数据倾斜时进行负载均衡
set hive.groupby.skewindata = true
开启负载均衡后,会生成两个 MRJob,第一个 MRJob,Map的输出结果会随机分配到 reduce 中,每个reduce 完成部分的聚合,并输出结果,这样相同的 GroupByKey 有可能分发到不同的 Reduce中。
第二个 MRJob 再根据预处理的数据结果按照 GroupByKey 分配到 Reduce 中,最后完成最终的聚合操作
- count distinct优化
count distinct 只需要用一个 reduce task 完成,在数据量大的情况下,会导致这个 reduce 处理的数据量太大,从而导致 Job 难以完成
select count(name) from (select name from A group by name) a;
- 控制 null 值的分布
可以提前过滤掉 null 值,或者将 null 值转换,使其随机分布
笛卡尔积
尽量避免笛卡尔积,join 时要加 on 条件,并且必须是有效的 on 条件
使用分区表分桶表
- 分区表可以将数据根据设定的分区分配到不同的文件夹中,查询时可以通过指定的分区进行读取
- 分桶表是将数据按指定列的 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
合并小文件
- map 执行前合并小文件,减少 map 数
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
- 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;