友情链接
•分布式计算框架系列文章(二)数据倾斜现象诱因、原理、影响,以及星环对此的应对策略
•分布式计算框架系列文章(三)星环科技计算引擎针对数据倾斜现象的保护机制
•分布式计算框架系列文章(四)当出现数据倾斜时如何应对--倾斜key单独处理/MapJoin/星环SkewJoin的原理及使用方法
示例一
原sql
select ... from A join B on A.key = B.key
where A.userid>10
and B.userid<10 and A.dt='20120417'and B.dt='20120417';
优化后sql
select .... from (select .... from A where dt='201200417'and userid>10) a
join
(select .... from B where dt='201200417'and userid < 10) b
on a.key = b.key;
优化原因
尽量尽早地过滤数据,减少每个阶段的数据量,对于分区表要加分区,同时只选择需要使用到的字段
示例二
优化背景
如日志中,常会有信息丢失的问题,比如全网日志中的user_id,如果取其中的user_id和bmw_users关联,就会碰到数据倾斜的问题。
原sql
select * from log a join bmw_users b
on a.user_id = b.user_id
优化后sql
解决方法1
select * from log a join bmw_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
select * from log a
left outer join bmw_users b
on case when a.user_id is null then concat('dp_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上 ,解决数据倾斜问题。因为空值不参与关联,即使分到不同的reduce上,也不影响最终的结果。
附上hadoop通用关联的实现方法(关联通过二次排序实现的,关联的列为paritionkey,关联的列c1和表的tag组成排序的group key,根据parition key分配reduce。同一reduce内根据group key排序)
示例三
优化背景
比如推广效果表要和商品表关联,效果表中的auction id列既有商品id,也有数字id,和商品表关联得到商品的信息。
建议写法
select * from effect a
join (
select auction_id as auction_id from auctions
union all
select auction_string_id as auction_id from auctions
) b
on a.auction_id = b.auction_id
优化原因
这样写的好处,1个MR作业,商品表只读取一次,推广效果表只读取一次。把这个sql换成MR代码的话,map的时候,把a表的记录打上标签a,商品表记录每读取一条,打上标签b,变成两个<key ,value>对,<b,数字id>,<b,字符串id>。所以商品表的hdfs读只会是一次
示例四
优化背景
先join生成临时表,在union all还是写嵌套查询
原sql
select * from (
select * from t1
union all
select * from t4
union all
select * from t2
join t3
on t2.id = t3.id
)
优化后sql
insert overwrite table t5
select * from t2
join t3
on t2.id = t3.id;
select * from (t1 union all t4 union all t5) ;
优化原因
inceptor在union all优化上可以做得更智能(把子查询当做临时表),这样可以减少开发人员的负担。出现这个问题的原因应该是union all目前的优化只局限于非嵌套查询。如果写MR程序这一点也不是问题,就是multi inputs。
示例五
优化背景
使用map join解决数据倾斜的常景下小表关联大表的问题,但如果小表很大,怎么解决
原sql
select * from log a
left outer join members b
on a.memberid = b.memberid members有600w+的记录
优化后sql
select /*+mapjoin(x)*/* from log a
left outer join (
select /*+mapjoin(c)*/ d.*
from (
select distinct memberid from log
) c
join members d
on c.memberid = d.memberid
)x
on a.memberid = b.memberid
优化原因
先根据log取所有的memberid,然后mapjoin 关联members取今天有日志的members的信息,然后在和log做mapjoin。
假如,log里memberid有上百万个,这就又回到原来map join问题。所幸,每日的会员uv不会太多,有交易的会员不会太多,有点击的会员不会太多,有佣金的会员不会太多等等。所以这个方法能解决很多场景下的数据倾斜问题。
其他优化建议
尽量原子化操作,尽量避免一个SQL包含复杂逻辑,可以使用中间表来完成复杂的逻辑;
join操作,小表要注意放在join的左边(目前TCL里面很多都小表放在join的右边)。否则会引起磁盘和内存的大量消耗;