技术02期:这么做竟然能让你的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

想了解更多技术干货文章, 请关注普适极客~

猜你喜欢

转载自blog.csdn.net/PUSHIAI/article/details/106215054