FAQ-SQOOP数据倾斜

场景

假设MySQL的表的字段orderid的数据如下表所示,orderid的10000到20000是连续的,但orderid从2直接跳到了10000,从20000直接跳到了100000

orderid
1
2
10000
10001
10002
......
20000
100000
SQOOP抽取这个表,如果-m(并行度)设置为10,且按照orderid进行split(切分键),则SQOOP的运行过程大致如下:
  1、运行boundary-query来找出表的最小最大值。
    select min(orderid),max(orderid) from order;
    查出最小值1,最大值100000
  2、进行切分并拉取数据,由于并发为10,此时会产生10个query,分别如下:
    select * from order where orderid>=1 and orderid<10000; — 2行数据

    select * from order where orderid>=10000 and orderid<20000; – 10000行数据

    select * from order where orderid>=20000 and orderid<30000; – 1行数据

    select * from order where orderid>=30000 and orderid<40000; – 0行数据

    ......

    select * from order where orderid>=90000 and orderid<100000; – 1行数据
    可以看出并行度为10点时候,只有与第2个查询会有10000行数据,其他的查询的数据都非常少,甚至没有。
  3、jdbc连上MySQL后,获取数据到HDFS。

如何排查数据倾斜:
  1、被用于切分的字段倾斜严重。如上面的场景所描述。
  2、切分键的字段为非整形,如果字段是字符串型,SQOOP会先hash之后再切分,内部算法较为复杂,且不能保证切分均匀。
解决方案:
  1、合理选择切分键,尽量保证均匀;
  2、尽量选择整形字段进行切分;
  3、尽量保证选择的切分键有索引。
  4、一些奇怪的用法:假如一张表有一个字段是int,其他全是varchar,而这个int字段又不均匀,也可以考虑将split-by的字段改成 right(xx,1),这样相当于一定把数据切分为了10份。而且最大值是9,最小值是0。此时可以指定参数:

--boundary-query "select 0,9 from dual" --split-by "right(id,1)"