解决数据倾斜

发布于:2023-01-14 ⋅ 阅读:(456) ⋅ 点赞:(0)

小表 Join 大表
将小表放在左边,使用map join,让小表进入内存,在map阶段完成join,省去了reduce阶段。
map join:
先开启一个本地任务,将小表扫描的内存。
然后开启一个没有reduce的MR任务扫描大表,将大表中的记录和内存的数据进行关联。
在这里插入图片描述
大表 Join 大表
空key过滤需要注意:
非inner join;
不需要空值。
空key转换:
key为空值会由一个Reduce Task处理,当空key太多,就会造成数据倾斜。给空key赋上一个随机值。

group by
同一个key发给一个reduce,当key数据量太大了,就造成了数据倾斜。
开启Map端聚合,在数据倾斜的时候开启负载均衡。
负载均衡:生成的查询计划会有两个MR任务。第一个MR Job,map的输出结果会随机分布到reduce中,reduce做部分聚合。这样做的结果是同一key可能分布在不同的reduce中,第二个MR Job再通过reduce by key将相同的key聚合到一块。

Count(Distinct )去重统计
去重需要一个Reduce Task,当重复的数据太多时,就会发生数据倾斜。
一般要进行 count distinct,会用先group by,再count的方式替换。
在这里插入图片描述

实例

  1. 空值产生的数据倾斜
    将控制赋予新的值,字符串+随机数
    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. 不同类型的数据关联产生的数据倾斜
    场景:用户表中 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)

  3. 小表不小不大,怎么用map join解决数据倾斜(不明白)
    select /+mapjoin(x)/* from log a
    left outer join (
    select /+mapjoin©/d.*
    from ( select distinct user_id from log ) c
    join users d
    on c.user_id = d.user_id
    ) x
    on a.user_id = b.user_id;
    假如,log 里 user_id 有上百万个,这就又回到原来 map join 问题。所幸,每日的会员 uv 不会太多,有交易的会员不会太多,有点击的会员不会太多,有佣金的会员不会太多等等。所以这个方法能解决很多场景下的数据倾斜问题。