Hive优化
一、常见的Hive的优化方式有哪些
- 开启执行计划
➢explain select … - Fetch模式
➢默认是开启的,开启后在全局查找、字段查找、limit查找等都不走MapReduce
set hive.fetch.task.conversion=more; 默认为more
- 本地模式
➢数据量小的时候通过本地模式在单台机器上处理所有的任务
//开启本地mr
set hive.exec.mode.local.auto=true;
//设置 local mr 的最大输入数据量,当输入数据量小于这个值时采用 local mr 的方式
//默认为 134217728,即 128M
set hive.exec.mode.local.auto.inputbytes.max=50000000;
//设置 local mr 的最大输入文件个数,当输入文件个数小于这个值时采用 local mr 的方式,默认为4
set hive.exec.mode.local.auto.input.files.max=8;
- 并行执行
➢当某个job包含众多的阶段且这些阶段不是完全互相依赖的,就可以并行执行,以缩短整个job的执行时间
set hive.exec.parallel=true;//打开任务并行执行,默认为false关闭
set hive.exec.parallel.thread.number=16;//设置最大并行度,默认为8
- 严格模式
➢默认是严格模式,是为了防止用户执行会产生意外影响的查询。严格模式可以限制以下几点- 不允许扫描所有分区,防止全表扫描消耗过大的资源
- orderby必须使用limit语句,orderby会将数据分发到同一个Reducer里,强制使用limit可以防止Reducer额外执行很长一段时间
- 限制笛卡尔积查询。因为Hive不会把where语句转化为on语句
- JVM重用
➢默认配置是使用派生的JVM来执行任务,这种方式下JVM的启动过程会造成很大的开销,尤其是task很多的情况。JVM实例的使用次数可以在hadoop的mapred-site.xml文件中进行配置,通常在10-20之间。
set mapred.job.reuse.jvm.num.tasks;默认为1
- 推测执行
➢负载不均衡或资源分布不均等原因,任务之间的运行速度不一致。对于明显慢的task,采用推测执行(speculative Execution)机制,推测出拖后腿的任务并启动一个备份任务,和原始任务共同处理同一份数据,最终选用先成功运行完成的计算结果作为最终结果 - 文件压缩
➢针对IO密集型的job,采取文件压缩的方式增加吞吐量和性能,减少载入内存的数据量;计算密集型的job不适合,因为压缩和解压会消耗CPU的使用
➢常见的文件存储格式有:TextFile、Sequence Files、RCFile、ORCFile、Parquet
- 合并小文件
小文件的产生有三个地方,map输入,map输出,reduce输出,小文件过多也会影响hive的分析效率:
设置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
- 表的优化
二、表的优化
数据倾斜在后面,此处不包含
-
大表+大表
➢空key过滤或空key转换 -
Count(Distinct)去重统计
➢数据量大时,一个Count(Distinct)对应的ReduceTask需要处理的数据量太大,导致job很难完成。因此需要采用先Groupby再count的方式替代 -
避免笛卡尔积
➢Hive只能使用1个Reducer完成笛卡尔积,会导致计算性能变低 -
行列过滤
➢在select中只拿需要的列,尽量不用select *;先子查询,将查询后的表再关联主表,提高效率,如果直接join再用where子句过滤,则会先全表关联再过滤,效率较低 -
动态分区调整
➢不同分区在不同文件夹内,在很多情况下可以避免全表扫描,提高查询效率 -
谓语下推
➢像where等句,提前处理,减少下游语句的负载量
select *
from (
select id,name
from test
where dt>=20200201 and dt<20200301
)T
inner join test2 on T.id=test2.id;
三、如何防止数据倾斜
3.1、产生数据倾斜的原因
- key 分布不均匀
- 业务数据本身的特性
- 建表时考虑不周
- 某些 SQL 语句本身就有
3.2、数据倾斜通用的处理方法
- 小文件进行合并,减少map数
- 复杂文件增加map数
- 设置适当的reduce个数
3.3、产生数据倾斜的场景和解决方案
3.3.1 group by 产生数据倾斜
➢根据业务合理调整分组维度
➢加盐
➢开启Map端聚合参数设置
- group by时某一个key的数量过多导致对应的reducer负载过大时,采取map端部分聚合的策略。
- 使用Map Combine进行map预聚合,可以减少磁盘IO传输
//是否在 Map 端进行聚合,默认为
True set hive.map.aggr = true;
//在 Map 端进行聚合操作的条目数目
set hive.groupby.mapaggr.checkinterval = 100000;
//有数据倾斜的时候进行负载均衡(默认是 false)
set hive.groupby.skewindata = true;
3.3.2 select语句中包含 count(distinct)时
➢使用sum(1)… group by替代
➢把倾斜的数据单独拿出来处理,最后union回去
3.3.3 大表+小表
➢mapjoin
3.3.4 大表+大表
➢把左边的join字段拎出来,这样得到的新表就是左边大表的几分之一或者几十分之一,把提取后的小表传到各个节点内存里使用mapjoin。最后通过左边的表leftjoin右边mapjoin的结果就可以了
➢最后leftjoin 左右两个大表,右边大表在经过mapjoin后的join字段和左边的join字段顺序是一一对应的,因此不会发生shuffle也就是单纯的mapjoin了
3.3.5 空值产生数据倾斜
➢id为空的不参与关联
select * from log a
join user b on a.user_id is not null and a.user_id = b.user_id
union all
select * from log c
where c.user_id is null;
➢给空值分配随机的key值,可以分配“平均值、中位数、随机数”,也可以concat其他列,hash值不一样了就
select *
from log a
join user b on case when a.user_id is null then concat('hive',rand()) else a.user_id=b.user_id;
3.3.6 不同数据类型关联产生数据倾斜
➢比如说有的表关联字段id是int而另一个是string,join时关联不上就会分到一个分区造成数据倾斜
3.3.7 开启负载均衡
set hive.groupby.skewindata=true;
开启内置分组聚合负载均衡的配置,默认为false;生成2个MR;但缺点是只能针对一列分组,多列分组会报错