惊,这么做竟然能让你的hive运行得更流畅!
导读
在大数据领域中,hive是基于Hadoop的一个数据仓库工具,主要用于对大数据量的处理工作,在平时设计和查询时要特别注意效率。数据倾斜、数据冗余、job或者I/O过多,MapReduce分配不合理等都会影响到hive效率。
本文主要介绍hql语句本身优化和hive配置优化提高hive效率。
▐ 谓词下推
就是将SQL语句中的where谓词逻辑都尽可能提前执行,减少下游处理的数据量。Hive中有谓词下推优化的配置项hive.optimize.ppd,默认值true,与它对应的逻辑优化器是PredicatePushDown。该优化器就是将OperatorTree中的FilterOperator向上提,见下图。
▐ Group by
(1) map端预聚合
group by时,如果先起一个combiner在map端做部分预聚合,可以有效减少shuffle数据量。预聚合的配置项是hive.map.aggr,默认值true。通过hive.groupby.mapaggr.checkinterval参数也可以设置map端预聚合的行数阈值,超过该值就会分拆job,默认值100000。
(2) 倾斜均衡配置项
group by时如果某些key对应的数据量过大,就会发生数据倾斜。配置均衡数据倾斜的配置项hive.groupby.skewindata=true。
其实现方法是在group by时启动两个MR job。第一个job会将map端数据随机输入reducer,每个reducer做部分聚合,相同的key就会分布在不同的reducer中。第二个job再将前面预处理过的数据按key聚合并输出结果,这样就起到了均衡的效果。
▐ Join
1、多表join时key相同
如果多表的join时候用的key相同,只会启动一个MR job来处理。
select *
from calendar_event_code a
inner join calendar_record_log b
on a.event_type = b.event_type
inner join calendar_record_log_2 c
on a.event_type = c.event_type;
如果上面两个join的条件不相同,比如改成a.event_code = c.event_code,就会拆成两个MR job计算。
2、利用map join
Map join特别适合大小表join的情况。Hive会将大小表在map端直接完成join过程,避免shuffle过程和reduce端计算,大大的提高效率。
map join,配置hive.auto.convert.join=true。还有一些参数用来控制map join的行为,比如hive.mapjoin.smalltable.filesize,当小表大小小于该值就会启用map join,默认值25000000(25MB)。还有hive.mapjoin.cache.numrows,表示缓存小表的多少行数据到内存,默认值25000。
3、倾斜均衡配置项
配置hive.optimize.skewjoin=true
如果开启了,在join过程中Hive会将计数超过阈值hive.skewjoin.key(默认100000)的倾斜key对应的行临时写进文件中,然后再启动另一个job做mapjoin生成结果。通过hive.skewjoin.mapjoin.map.tasks参数还可以控制第二个job的mapper数量,默认10000。
4、优化sql处理join的数据倾斜
(1) 空值或者无意义值
若不需要空值数据,就提前写where语句过滤掉。需要保留的话,将空值key用随机方式打散
select a.uid,a.event_type,b.nickname,b.age
from (select
(case when uid is null then cast(rand()*-10240 as int) else uid end) as uid,
event_type from calendar_record_log
) a
left outer join user_info b
on a.uid = b.uid;
(2) 单独处理数据倾斜key
这其实是上面处理空值方法的拓展,不过倾斜的key变成了有意义的。我们可以将它们抽样出来,对应的行单独存入临时表中,然后打上一个较小的随机数前缀(比如0~9),最后再进行聚合。SQL语句与上面的相仿
(3) 不同数据类型
举个例子,假如我们有一旧一新两张日历记录表,旧表的记录类型字段是(event_type int),新表的是(event_type string)。为了兼容旧版记录,新表的event_type也会以字符串形式存储旧版的值,比如'17'。当这两张表join时,经常要耗费很长时间。其原因就是如果不转换类型,计算key的hash值时默认是以int型做的,这就导致所有“真正的”string型key都分配到一个reducer上。
select a.uid,a.event_type,b.record_data
from calendar_record_log a
left outer join calendar_record_log_2 b
on a.uid = b.uid and b.event_type = cast(a.event_type as string);
(4) 小表过大
小表会大到无法直接使用map join的地步,而使用普通join又有数据分布不均的问题。这时就要充分利用大表的限制条件,削减小表的数据量,再使用map join解决。代价就是需要进行两次join。
select /*+mapjoin(b)*/ a.uid,a.event_type,b.status,b.extra_info
from calendar_record_log a
left outer join
( select /*+mapjoin(s)*/ t.uid,t.status,t.extra_info
from
( select distinct uid from calendar_record_log
where pt_date = 20190228
) s
inner join user_info t
on s.uid = t.uid
) b
on a.uid = b.uid
where a.pt_date = 20190228;
总结:本文主要介绍hql语句本身优化和hive配置优化来提高hive效率。但job或者I/O过多,MapReduce分配不合理等都会影响到hive效率。无论哪一种优化方法都要根据具体的应用场景决定。
参考资料:
https://tech.meituan.com/2014/02/12/hive-sql-to-mapreduce.html
https://www.cnblogs.com/swordfall/p/11037539.html
想了解更多技术干货文章, 请关注普适极客~