淘先锋技术网

首页 1 2 3 4 5 6 7

理解join的运行原理

select u.name, o.orderid from order o join user u on o.uid = u.uid;
join运行原理

理解join的作用?

通常我们在执行join的时候,通常是一个表a包含很多的key, 这个key是可重复的,一张表b中对应的key是不能重复且唯一的。(如果两张表包含多个相同的key进行join操作,会产生笛卡尔积, 产生多个结果,显然在生产环境中,这是我们不想看到的)

为什么会产生数据倾斜?

造成Join数据倾斜的原因是Join on的key分布不均匀。 mapreduce底层是根据 key的hash值%reduce个数 来进行数据分区的,所以相同的key对打到同一个reduce进行处理。
key值分布不均匀,倾斜key数据都被打到同一个reduce上进行处理, 造成数据倾斜问题。

场景1: 一张大表一张小表的情况?

采用MapJoin的方式, 将小表加载到内存中,执行map端的join, 中间不产生shuffle, 就不会有数据倾斜的情况出现了。

场景2: 两张大表,部分key导致倾斜的情况?

倾斜的key落到一个reduce task上, 导致某一个reduce Task执行缓慢。
对导致倾斜的key单独处理(这里的详细的处理方式就是场景3的处理方式),和没有导致倾斜的key执行的结果进行 union all。
例如key空值过多导致的数据倾斜问题。

优点:对于join导致的数据倾斜,如果只是某几个key导致了倾斜,采用该方式可以用最有效的方式打散key进行join。而且只需要针对少数倾斜key对应的数据进行扩容n倍,不需要对全量数据进行扩容。避免了占用过多内存。

缺点:如果导致倾斜的key特别多的话,比如成千上万个key都导致数据倾斜,那么这种方式也不适合。

场景3: 两张大表,很多个key导致倾斜的情况?

有很多倾斜key的表a, key分布均匀的表b

1、给表a的key加上100以内的随机前缀,将数据打散 (ceiling函数,向上取整)
select concat_ws("_", ceiling(rand()*99), key) from a;                   tmp_a

2、将表b扩容100倍,给key加上100以内的随机前缀

产出一张临时表, tmp_id, 表中的内容如下: 
id
1
2
3
4
...
99
100

将表b和表tmp_id进行join, 产生笛卡尔积
select concat_ws("_", c.id, b.key) as key, value from b join tmp_id c;     tmp_b

这样表b的数据就扩容了100倍

然后将 tmp_a 和 tmp_b 进行join: 

select a.key, a.value, b.value 
from tmp_a a join tmp_b b 
on a.key = b.key;

这样的话,key就均匀地分配到不同的reduce上了,而且都能和对应的数据关联上,注意执行完成之后,对相应的key进行去掉前缀的操作。

由于对表b进行了扩容,这里需要对reduce端的内存做相应的调整,增加reduce task的内存。

场景3的解决方案的缺点:

优点:对join类型的数据倾斜基本都可以处理,而且效果也相对比较显著,性能提升效果非常不错。

缺点:该方案更多的是缓解数据倾斜,而不是彻底避免数据倾斜。而且需要对整个RDD进行扩容,对内存资源要求很高。