Hive - 数据倾斜的原因以及解决办法(附样例)
在大数据处理的过程中,Hive 是一种常用的工具。然而,在处理大规模数据时,数据倾斜问题往往会导致查询性能下降,甚至查询失败。本文将介绍 Hive 数据倾斜的原因,并提供几种有效的解决方案。
(2)hive.groupby.skewindata 参数参数设置为 true 时,Hive 会在执行 Group By 操作时检测并处理数据倾斜。具体来说其生成的查询计划会有两个 MR Job:
一、数据倾斜原因分析
1,可能会触发 Hive 数据倾斜的情况
关键字 | 情形 | 后果 |
join | 大表与小表,小表中的 key 集比较集中 | 分发到某一个或几个 Reduce 上的数据远高于平均值 |
join | 大表与大表,但是 join 中指定的字段 0 值或空值过多 | 这些空值都由一个 reduce 处理,非常慢 |
group by | group by 维度过小,处理的数量过多 | 处理某值的 reduce 非常耗时 |
2,造成数据倾斜的原因
(1)key 分布不均匀
(2)业务数据本身的特性
(3)建表时考虑不周
(4)某些 SQL 语句本身就有数据倾斜
3,数据倾斜的表现
(1)任务进度长时间维持在 99%(或 100%),查看任务监控页面,发现只有少量(1 个或几个)reduce 子任务未完成。因为其处理的数据量和其他 reduce 差异过大。
(2)单一 reduce 的记录数与平均记录数差异过大,通常可能达到 3 倍甚至更多。 最长时长远大于平均时长。
二、数据倾斜的解决方案
1,调整 Hive 配置
(1)hive.map.aggr 参数用于在 Map 阶段进行部分聚合,可以有效地减少需要传输到 Reduce 阶段的数据量,从而减轻 Reduce 阶段的负担。
SET hive.map.aggr=true;
(2)hive.groupby.skewindata 参数参数设置为 true 时,Hive 会在执行 Group By 操作时检测并处理数据倾斜。具体来说其生成的查询计划会有两个 MR Job:
- 第一个 MR Job 中,Map 的输出结果集合会随机分布到 Reduce 中,每个 Reduce 做部分聚合操作,并输出结果,这样处理的结果是相同的 Group By Key 有可能被分发到不同的 Reduce 中,从而达到负载均衡的目的;
- 第二个 MR Job 再根据预处理的数据结果按照 Group By Key 分布到 Reduce 中(这个过程可以保证相同的 Group By Key 被分布到同一个 Reduce 中),最后完成最终的聚合操作。
SET hive.groupby.skewindata=true;
2,SQL 语句调节
(1)针对大小表 Join:
- 使用 map join 让小的维度表(1000 条以下的记录条数) 先进内存,在 map 端完成 join 操作。正常情况下 join 是需要在 reduce 端执行的,通过 map join 可以实现在 map 端执行 join 操作,这样可以避免在 shuffle 的时候造成数据倾斜。
(2)针对大表 Join 大表:
- 把空值的 key 变成一个字符串加上随机数,把倾斜的数据分到不同的 reduce 上,由于 null 值关联不上,处理后并不影响最终结果。
(3)优化 Group By 操作:
- 下面 SQL 其实是一个解决数据倾斜的 SQL(添加随机数,两阶段聚合)。先看里面的 select 语句,里面的 select 语句其实是根据 key 进行分组,但是这个 key 对应的数据存在数据倾斜,key=KEY001 的数据占了整份数据的 90%,所以直接针对 key 进行分组肯定会出现数据倾斜,应该计算效率,所以在这里就实现了曲线救国,先把 key=KEY001 的数据打散,分成 50 份,进行局部聚合。最后再通过外面的 select 进行全局的聚合,这样就可以显著提高计算效率。
SELECT a.Key , SUM(a.Cnt) AS Cnt FROM ( SELECT Key , COUNT(*) AS Cnt FROM TableName GROUP BY Key, CASE WHEN Key = 'KEY001' THEN Hash(Random()) % 50 ELSE 0 END ) a GROUP BY a.Key;