Hive数据倾斜原因及优化解决方案

一:什么是数据倾斜

数据倾斜是进行大数据计算时常见的问题。主要分为map端倾斜和reduce端倾斜,map端倾斜主要是因为输入文件大小不均匀导致,造成部分数据大量的集中在某一个节点上,形成了数据热点,导致这一节点运行时间远远大于其他节点的时间reduce端主要是partition不均匀导致。

二:Hive中有那些容易造成数据倾斜的情况以及处理办法

1:map端数据倾斜

当maptask出现较多的小文件时,需要合并小文件,可以通过设置
set hive.merge.mapfiles=true来解决,
set hive.map.aggr=true;//map端聚合:相当于Combiner,可以减小map端的压力,
set hive.groupby.skewindata=true;负载均衡
//有数据倾斜的时候进行负载均衡,当选项设定为true,生成的查询计划会有两个MR job。
第一个job中,map端的输出结果集合会随机分布到Reduce中,每个reduce都做部分聚合,
并输出结果,这样的处理结果是相同的group by key有可能被分布到不同的reduce中,
从而达到负载均衡的目的,第二个MR job再根据预处理的数据结果按照group by key
分布到reduce中(这个过程可以保证相同的group by key被分布到同一个reduce中),
最后完成最终的聚合操作。
-------------------------------------------------------------------
/当单个文件大小稍大于block的大小可以适当的增加map的个数:
set mapred.map.tasks个数
/当文件大小适中,map端计算量较大的时候(sum,count等),需要增加map个数:
set mapred.map.tasks个数,set mapred.reduce.tasks个数
--------------------------------------------------------------------

2:大小表关联

小表在join左侧,大表在右侧,或使用mapjoin 将小表加载到内存中。然后再对比较大的表进行map操作
join就发生在map操作的时候,这里的join并不会涉及reduce操作。map端join的优势就是在于没有shuffle

如:select /*+ MAPJOIN(a) */ 	 hive0.11 版本之前
a.c1, b.c1 ,b.c2 from a join b 
where a.c1 = b.c1; 

map join 概念:将其中做连接的小表(全量数据)分发到所有 MapTask 端进行 Join,从 而避免了 reduceTask,前提要求是内存足以装下该全量数据,在内存允许的条件下使用 map join 比直接使用 MapReduce 效率还高些, 当然这只限于做 join 查询的时候。

在 hive0.11 版本以后会自动开启 map join 优化,由两个参数控制:
set hive.auto.convert.join=true;
 //设置 MapJoin 优化自动开启
set hive.mapjoin.smalltable.filesize=25000000 
//设置小表不超过多大时开启 mapjoin 优化

3:大大表关联

大表化小表,抽取左表一列字段与右表map join,再与左表left join,即可

4:大量KEY的值为null

null值的数据就会统一分布在一个节点,导致节点运行时间过长

解决方法1:子查询中过滤掉null值,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;
解决方法2:用case when给空值分配随机的key值(字符串+rand())
select * from
log a left outer join user b
on case when a.user_id is null
   then concat('hive',rand())
   else a.user_id end = b.user_id

方法 2 比方法 1 效率更好,不但 IO 少了,而且作业数也少了,方案 1 中,log 表 读了两次,jobs 肯定是 2,而方案 2 是 1。这个优化适合无效 id(比如-99,’’,null)产 生的数据倾斜,把空值的 key 变成一个字符串加上一个随机数,就能把造成数据倾斜的 数据分到不同的 reduce 上解决数据倾斜的问题。

改变之处:使本身为 null 的所有记录不会拥挤在同一个 reduceTask 了,
会由于有替代的 随机字符串值,而分散到了多个 reduceTask 中了,
由于 null 值关联不上,处理后并不影响最终结果。

5:不同数据类型关联产生数据倾斜

解决方案:关联字段数据类型转换一致

6:当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;

7:join和Group的优化

2.1 对于普通的join操作,会在map端根据key的hash值,shuffle到某一个reduce上去,在reduce端做join连接操作,内存中缓存join左边的表,遍历右边的表,一次做join操作。所以在做join操作时候,将数据量多的表放在join的右边。
当数据量比较大,并且key分布不均匀,大量的key都shuffle到一个reduce上了,就出现了数据的倾斜。

在map端产生join

mapJoin的主要意思就是,当链接的两个表是一个比较小的表和一个特别大的表的时候,
我们把比较小的table直接放到内存中去,然后再对比较大的表格进行map操作。
join就发生在map操作的时候,每当扫描一个大的table中的数据,就要去去查看小表的数据,
哪条与之相符,继而进行连接。这里的join并不会涉及reduce操作。
map端join的优势就是在于没有shuffle,

2.2 对于Group操作,首先在map端聚合,最后在reduce端坐聚合,hive默认是这样的,以下是相关的参数

hive.map.aggr = true是否在 Map 端进行聚合,默认为 True 
hive.groupby.mapaggr.checkinterval = 100000在 Map 端进行聚合操作的条目数目

你可能感兴趣的:(性能优化,hive)