Hive数据倾斜调优

1.数据倾斜分哪几类以及如何优化?

开发人员首先要确认几点:

  1. 需要计算的指标真的需要从数据仓库的公共明细层来自行汇总吗?数据团队开发的公共汇总层是否可以满足其要求了?

  2. 真的需要扫描这么多分区吗?能扫描一周的就不扫描一年的。

  3. 尽量不要使用select * from table这样的词语,能指定哪一列就用那一列,尽量添加过滤条件。

  4. 输入文件不要大量小文件,小文件可以先合并成大文件。

如果以上问题都排完雷了,数据倾斜问题依然存在,那我们继续往下看~

2.数据倾斜的原因

2.1操作

关键词

情形

后果

Join

其中一个表较小,

但是key集中

分发到某一个或几个Reduce上的数据远高于平均值

大表与大表,但是分桶的判断字段0值或空值过多

这些空值都由一个reduce处理,灰常慢

group by

group by 维度过小,

某值的数量过多

处理某值的reduce灰常耗时

Count Distinct

某特殊值过多

处理此特殊值的reduce耗时

2.2原因

  1. key分布不均匀
  2. 业务数据本身的特性
  3. 建表时考虑不周
  4. 某些SQL语句本身就有数据倾斜

2.3表现

任务进度长时间维持在99%(或100%),查看任务监控页面,发现只有少量(1个或几个)reduce子任务未完成。因为其处理的数据量和其他reduce差异过大。

单一reduce的记录数与平均记录数差异过大,通常可能达到3倍甚至更多。 最长时长远大于平均时长。

3.解决方案

3.1和join无关的优化场景

3.1.1group by引起的倾斜优化

举例:比如按照经销商的供应商来做group by,那么有些大经销商就有很多订单,而一些小经销商只有几个订单,那么分配给发大经销商的reduce task就有许多订单,所以造成数据倾斜。

解决:参数设置

  • Map 端部分聚合,相当于Combiner
hive.map.aggr = true
  • 有数据倾斜的时候进行负载均衡,当选项设定为 true,生成的查询计划会有两个 MR Job。第一个 MR Job 中,Map 的输出结果集合会随机分布到 Reduce 中,每个 Reduce 做部分聚合操作,并输出结果,这样处理的结果是相同的 Group By Key 有可能被分发到不同的 Reduce 中,从而达到负载均衡的目的;第二个 MR Job 再根据预处理的数据结果按照 Group By Key 分布到 Reduce 中(这个过程可以保证相同的 Group By Key 被分布到同一个 Reduce 中),最后完成最终的聚合操作。
hive.groupby.skewindata=true

3.1.2count distinct的优化

在开发过程中,要小心使用count distinct。

举例:

select count(distinct user) from table

解决:SQL优化

由于必须要去重了,所以hive会把所有的map阶段输出都放在一个reduce上,造成性能问题,所以通过group by再count进行优化。

select count(*)from(  select user  from table  group by user) tmp

3.2和join有关的优化场景

3.2.1大表join小表优化

举例:有两个表,一个是供应商,一个是订单,供应商的表不会很大,因为供应商就这么点儿人,而订单的表就很大了。两个表join一下,就是一个很经典的大表join小表问题。

解决:mapjoin hint的方式

select /*+mapjoin(b小表)*/

3.2.2大表join大表优化

举例:有两个表,A表表示买家卖家的交易汇总表,B表表示卖家的段位评级。想要获得卖家在各个级别卖家的成交比例。

如某个买家:金冠店:40%,皇冠店:30%,钻石店:20%,星级店:10%

这两个表都会很大,超过mapjoin1G的限制,所以需要找其他方法解决。

  • 方案一:hive.optimize.skewjoin参数配置

如果大表和大表进行join操作,则可采用skewjoin

skewjoin原理

  1. 对于skewjoin.key,在执行job时,将它们存入临时的HDFS目录。其它数据正常执行

  2. 对倾斜数据开启map join操作,对非倾斜值采取普通join操作

  3. 将倾斜数据集和非倾斜数据及进行合并操作

该参数为在运行时动态指定数据进行skewjoin,一般和hive.skewjoin.key参数一起使用

  set hive.optimize.skewjoin=true;
  set hive.skewjoin.key=100000;

以上参数表示当记录条数超过100000时采用skewjoin操作

  • 方案二:mapjoin hint的方式
此思路有两种途径:限制行和列

限制行的思路是比如不需要join b表全部,只需要join a表中存在的就行,比如过滤掉90天内没交易过的卖家

限制列的思路是只取需要的字段
  • 方案三:join时候用case when语句随机数

解决场景是倾斜的值明确且数量很少,如用null引起的值。

核心是将这些倾斜的值发放到随机的reduce,具体做法是在join时对这些特殊的值concat随机数,从而达到随即分发的目的。

on (case when a.user_id is null then concat('hive',rand()) else a.user_id end) = b.user_id
  • 方案四:动态一分为二

最彻底的方式就是动态一分为二,将倾斜和不倾斜的值分开处理,如果不倾斜的直接正常join,如果倾斜的找出来做mapjoin,最后结果union all即可。

4.典型业务场景

4.1空值产生的数据倾斜

场景:如日志中,常会有信息丢失的问题,比如日志中的 user_id,如果取其中的 user_id 和 用户表中的user_id 关联,会碰到数据倾斜的问题。

解决方法1: user_id为空的不参与关联

select * from log a
  join users b
  on a.user_id is not null
  and a.user_id = b.user_id
union all
select * from log a
  where a.user_id is null;

解决方法2 :赋与空值分新的key值

select *
from log a
left outer join users 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 job数是1 。这个优化适合无效 id (比如 -99 , ’’, null 等) 产生的倾斜问题。把空值的 key 变成一个字符串加上随机数,就能把倾斜的数据分到不同的reduce上 ,解决数据倾斜问题。

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

场景:用户表中user_id字段为int,log表中user_id字段既有string类型也有int类 型。当按照user_id进行两个表的Join操作时,默认的Hash操作会按int型的id来进行分配,这样会导致所有string类型id的记录都分 配到一个Reducer中。

解决方法:把数字类型转换成字符串类型

select * 
from users a
left outer join logs b on a.usr_id = cast(b.user_id as string)

 

posted @   民宿  阅读(436)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示