hive调优总结
不定期更新
一、参数优化
参数 | 说明 |
set hive.exec.dynamic.partition=true | 是否开启动态分区功能,默认false关闭。 |
set hive.exec.dynamic.partition.mode=nonstrict | 动态分区的模式,默认strict,表示必须指定至少一个分区为静态分区,nonstrict模式表示允许所有的分区字段都可以使用动态分区。 |
set hive.exec.max.dynamic.partitions=1000000 | 在所有执行MR的节点上,最大一共可以创建多少个动态分区。 |
set hive.exec.max.dynamic.partitions.pernode=1000000 | 在每个执行MR的节点上,最大可以创建多少个动态分区 |
set hive.merge.mapfiles = true | map-only job后合并文件 |
set hive.merge.mapredfiles = true | map reduce job 后合并文件 |
set hive.merge.size.per.task = 250000000 | 合并后每个文件的大小 |
set hive.merge.smallfiles.avgsize=200000000 | 平均文件大小,是决定是否执行合并操作的阈值 |
set hive.exec.parallel=true | 参数控制在同一个sql中的不同的job是否可以同时运行,默认false |
set mapred.job.parallel.thread.number=8 | 控制对于同一个SQL来说同时可以运行job的最大值 |
set mapred.job.reuse.jvm.num.tasks=8 | 因为 Hive 语句最终要转换为一系列的MapReduce Job 的,而每一个 MapReduceJob是由一系列的MapTask 和ReduceTask 组成的,默认情况下,MapReduce 中一个MapTask 或者一个ReduceTask 就会启动一个JVM进程,一个Task 执行完毕后,JVM进程就退出。这样如果任务花费时间很短,又要多次启动JVM 的情况下,JVM 的启动时间会变成一个比较大的消耗,这个时候,就可以通过重用JVM 来解决.(这个功能的一个缺点就是会一 直占用task插槽不释放,以备重用,直到任务完成才释放。如果在任务过程中出现数据倾斜,则可能task插槽需要等到reduce task任务完成才能释放) |
二、SQL写法优化
- 减少count distinct
在使用count 和distinct的时候,每次使用都会调用一个reduce任务来完成,一个reduce任务如果处理的数据量过大会导致整个job难以完成。
避免:
select count(distinct test_id) from
test_database.test_table_001
where date = "2022-01-04" and module="jankinspector";
替代:
select count(1)
from
(select test_id
from test_database.test_table_001
where date = "2022-01-04" and module="jankinspector"
group by test_id
) t ;
(数据量大的时侯distinct反而慢)
2.排序问题sort by 代替 order by
HiveSQL 中的order by 与其他SQL 语法中的功能一样,就是将结果按某字段全局排序,这会导致所有map 端数据都进入一个 reducer中,在数据量大时可能会长时间计算不完。
如果使用 sort by,那么还是会视情况启动多个reducer 进行排序,并且保证每个reducer 内局部有序。为了控制map 端数据分配到 reducer的key,往往还要配合 distribute by 一同使用。如果不加distribute by 的话,map 端数据就会随机分配到 reducer。
set mapreduce.job.reduces=10;
select model,id_count
from test_database.test_table
where date='2022-01-04'
distribute by model
sort by id_count desc
注意:
1. distribute by的分区规则是根据分区字段的hash码与reduce的个数进行模除后,余数相同
的分到一个区。
2. Hive要求DISTRIBUTE BY语句要写在SORT BY语句之前。