user_id | name | age | gender |
---|---|---|---|
1 | henry | 16 | 男 |
2 | jack | 17 | 男 |
3 | anny | 18 | 女 |
4 | candy | 19 | 女 |
5 | kate | 20 | 女 |
burke | 21 | ||
frank | 22 | ||
ellen | 23 | ||
ken | 24 | ||
mili | 25 | ||
... | ... | ... | ... |
user_id | subject_id | score |
1 | 1 | 89 |
1 | 2 | 90 |
1 | 3 | 91 |
4 | 2 | 92 |
4 | 3 | 93 |
6 | 1 | 94 |
7 | 3 | 95 |
8 | 1 | 96 |
8 | 2 | 97 |
8 | 3 | 98 |
... | ... | ... |
一、何为hive数据倾斜?
是因为数据分布的不均匀,导致一大部分数据集中到某一个节点上,其他数据少的节点早早的就完成了计算任务,数据量大的节点还在计算中,使得整个job进度长时间停留在 map100%,reduce99%,这就是因为数据发生了倾斜导致的结果。
导致数据倾斜有以下原因:
1.数据本身某个key值较多,导致分布不均,比如说上述info表中性别一列只有两个男生,两个女生,其余为空值。这样大量的空值字段会导致数据倾斜。
2.针对某个业务,导致某个key值较多,分布不均匀,比如说group by时某个字段值较多。比如说上述info表中男生数量只有几个,其余皆为女生。如果要按照性别分组,这样极易导致倾斜。
3.建表时考虑不周全
4.某些hql语句本身就有数据倾斜。
二、如何解决数据倾斜?
1.若数据中某个字段有大量空值,存在信息缺失的情况。导致在表之间进行关联时,发生数据倾斜。
比如,将info表和score表关联,那么info表中的user_id字段存在大量空值,会导致数据倾斜。
解决办法:要么先将空值过滤掉,最后再将空值union all进去。
select *
from info a
join score b
on a.user_id is not null and a.user_id=b.user_id
union all
select * from info c where c.user_id is null;
要么将空值分配一个字符串+随机数。
select *
from info a
left join score b
on
case when a.user_id is null then concat(hive,rand()) else a.user_id end =b.user_id;
第二种执行效率会更高一些,因为第一种会读两次表。而第二种只读一次表,且由于null值关联不上,处理后并不影响最终结果。
2.若两张表中在做join时,相关联的字段的数据类型不一致时会导致数据倾斜。
如果info表中user_id的属性是int,score表中user_id的属性是string,在做两表关联时,容易发生数据倾斜。
解决办法:将数据类型转成一致的类型,使用cast函数。
select *
from info a
left outer join score b
on b.user_id = cast(a.user_id as int)
3.当大小表关联查询时会发生数据倾斜。
解决办法:在map端完成join。这里是inner join。将小表加载到内存中,使得每个map task上都有此小表,小表分别和各个数据块做join。在hive的0.11版本后,会自动开启map join优化,具体参数设置如下:
set hive.auto.convert.join=true;(默认开启)
set hive.mapjoin.smalltable.filesize=25000000;//设置小表的大小,不超过则开启mapjoin
4.当大表和大表相关联时发生数据倾斜。
解决办法:将大表1中关联列去重后单独抽出,形成一张小表。将此小表和大表2先关联,关联好后再和大表1进行关联。
5.当对表中数据做一些类型统计的时候遇到过某种类型的数据量特别多,而其他类型数据的数据量特别少。当按照类型进行 group by 的时候,会将相同的 group by 字段的 reduce 任务需要的数据拉取到同一个节点进行聚合。比如说计算info表中男女生数量。(比如男生很少,女生很多)
解决办法:开启 Map 端聚合参数设置
//是否在 Map 端进行聚合,默认为 True
set hive.map.aggr = true;
//在 Map 端进行聚合操作的条目数目
set hive.groupby.mapaggr.checkinterval = 100000;
//有数据倾斜的时候进行负载均衡(默认是 false)
set hive.groupby.skewindata = true;
6.当hql语句中包含 count(distinct)时,如果数据量非常大,查询各个学生考了几门课程的考试。执行如 select user_id,count(distinct subject_id) from score group by score;类型的 SQL 时,会出现数据倾斜的问题。
解决办法:使用sum...group by 代替
select
user_id,sum(1)
from
(
select user_id,subject_id from score group by user_id,subject_id
)
group by user_id;