目录
1、常见的Hive调优方式
1.1 本地模式
- Hive支持将作业自动转换为本地模式运行
- 当要处理的数据很小时,完全分布式模式的启动时间比作业处理时间要长
--通过以下设置开启本地模式
SET hive.exec.mode.local.auto=true; --default false
SET hive.exec.mode.local.auto.inputbytes.max=50000000;
SET hive.exec.mode.local.auto.input.files.max=5; --default 4
- Job必须满足以下条件才能在本地模式下运行
- Job总输入大小小于 hive.exec.mode.local.auto. inputbytes.max
- map任务总数小于 hive.exec.mode.local.auto. input.files.max
- 所需的Reduce任务总数为1或0
1.2 JVM重用
- 通过JVM重用减少JVM启动的消耗
- 默认每个Map或Reduce启动一个新的JVM
- Map或Reduce运行时间很短时,JVM启动过程占很大开销
- 通过共享JVM来重用JVM,以串行方式运行MapReduce Job
- 适用于同一个Job中的Map或Reduce任务
- 对于不同Job的任务,总是在独立的JVM中运行
-- 通过以下设置开启JVM重用
set mapred.job.reuse.jvm.num.tasks = 5; -- 默认值为1
1.3 并行执行
- 并行执行可提高集群利用率
- Hive查询通常被转换成许多按默认顺序执行的阶段
- 这些阶段并不总是相互依赖的
- 它们可以并行运行以节省总体作业运行时间
- 如果集群的利用率已经很高,并行执行帮助不大
--通过以下设置开启并行执行
SET hive.exec.parallel=true; -- default false
SET hive.exec.parallel.thread.number=16; -- default 8,定义并行运行的最大数量
1.4 严格模式
开启严格模式可以禁止3种类型的查询
- 对于分区表,除非where语句中含有分区字段过滤条件来限制范围,否则不允许执行。换句话说,就是用户不允许扫描所有分区。进行这个限制的原因是,通常分区表都拥有非常大的数据集,而且数据增加迅速。没有进行分区限制的查询可能会消耗令人不可接受的巨大资源来处理这个表。
- 对于使用order by语句的查询,要求必须使用limit语句。因为 order by为了执行排序过程会将所有的结果数据分发到同一个 Reducer 中进行处理,强制要求用户增加这个 LIMIT 语句可以防止Reducer 额外执行很长一段时间。
- 限制笛卡尔积的查询。对关系型数据库非常了解的用户可能期望在执行JOIN 查询的时候不使用 ON 语句而是使用 where 语句,这样关系数据库的执行优化器就可以高效地将 WHERE 语句转化成那个 ON 语句。不幸的是,Hive 并不会执行这种优化,因此,如果表足够大,那么这个查询就会出现不可控的情况。
<property>
<name>hive.mapred.mode</name>
<value>strict</value>
</property>
1.5 采用压缩和适当的文件格式
压缩可以节约磁盘的空间,基于文本的压缩率可达 40%+; 压缩可以增加吞吐量和性能量(减小载入内存的数据量),但是在压缩和解压过程中会增加 CPU 的开销。所以针对 IO 密集型的 jobs(非计算密集型)可以使用压缩的方式提高性能。
使用适当的文件格式,如:orc, avro, parquet
使用适当的压缩格式,如:snappy
1.6 合理设置map和reduce数量
1.7 合理使用分区表和分桶表
1.8 explain执行计划
explain执行计划,通过执行计划来调节SQL语句,语法:explain 查询语句;
能看出每个阶段的执行计划,然后查询优化。
2、数据倾斜
2.1 产生原因
- 1、key分布不均匀
- 2、业务数据本身的特性
- 3、建表时考虑不周
- 4、某些SQL语句本身就有数据倾斜,例如:
- 大表join小表,其中小表key集中,分发到某一个或几个reduce上的数据远高于平均值。
- 大表join大表,但是分桶的判断字段0值或空值过多,这些空值都由一个reduce处理,非常慢。
- group by,group by维度过小,某值的数量过多,处理某值的reduce非常耗时。
- count distinct,某特殊值过多,处理此特殊值的reduce耗时。
2.2 解决方法
- 1.group by 产生数据倾斜
使用 Hive 对数据做一些类型统计的时候遇到过某种类型的数据量特别多,而其他类型数据的数据量特别少。当按照类型进行 group by 的时候,会将相同的group by 字段的 reduce 任务需要的数据拉取到同一个节点进行聚合,而当其中每一组的数据量过大时,会出现其他组的计算已经完成而这里还没计算完成,其他节点的一直等待这个节点的任务执行完成,所以会看到一直 map 100% reduce 99%的情况。
解决方法:
➢ 开启 Map 端聚合参数设置
➢ 或者根据业务,合理调整分组维度。 - 2.当 HiveQL 中包含 count(distinct)时
如果数据量非常大,执行如 select a,count(distinct b) from t group by a;类型的SQL 时,会出现数据倾斜的问题。
解决方法:
➢ 使用 sum…group by 代替。如 select a,sum(1) from (select a, b from t group by a,b) group by a;
➢ 在业务逻辑优化效果的不大情况下,有些时候是可以将倾斜的数据单独拿出来处理。最后 union 回去。 - 3.当遇到一个大表和一个小表进行 join 操作时
解决方法:
使用 mapjoin 将小表加载到内存中。 - 4.空值产生的数据倾斜
遇到需要进行 join 的但是关联字段有数据为空。
场景:如日志中,常会有信息丢失的问题,比如日志中的 user_id,如果取其中的 user_id 和 用户表中的 user_id 关联,会碰到数据倾斜的问题。数据量大时也会产生数据倾斜,如表一的 id 需要和表二的 id 进行关联。
解决方法:
➢ id 为空的不参与关联;
select * from log a join users b on a.user_id is not null and a.user_id = b.user_id union all select * from log a where a.user_id is null;
➢ 给空值分配随机的 key 值。
select * from log a left outer join users b on case when a.user_id is null then concat(‘hive’,rand() ) else a.user_id end = b.user_id;
一般分配随机 key 值得方法更好一些。 - 5.通用的一些数据倾斜的处理方法
➢ 合理设置 map 和 reduce 数