sqoop数据倾斜解决实战

  • 背景: 下面导致数据倾斜的sqoop任务,这个数据倾斜是由于源数据导致的- 源表的index1 分布不均匀,不均匀指每一块的数据量不均匀,范围[min(index),max(index)]被分为m块,每块index[0,7]的值在 [min+index*range/8,min+(index+1)*range] 间,如第一块100MB,最后一块1GB的数据量,数据量可在hdfs查看map文件大小。
    (数据量,用时):(一千万+条,20分钟)
sqoop import \
--connect "jdbc:mysql://${mysql_host}:${mysql_port}/${mysql_db}?zeroDateTimeBehavior=convertToNull&dontTrackOpenResources=true&tinyInt1isBit=false&defaultFetchSize=10000&useCursorFetch=true&autoReconnect=true&failOverReadOnly=false&useSSL=false" \
--driver com.mysql.jdbc.Driver \
--username ${mysql_user} \
--password ${mysql_password} \
--table ${mysql_table} \
--columns 'field1,field2,...,fieldn' \
--hcatalog-database test \
--hcatalog-table ${hive_table} \
--hcatalog-partition-keys 分区字段 \
--hcatalog-partition-values 分区字段值 \
-m 8 \
--split-by index1
  • solutionA: 使用–query语句中添加自增ID,作为split-by的参数
    用时:8分钟
sqoop import \
--connect "jdbc:mysql://${mysql_host}:${mysql_port}/${mysql_db}?zeroDateTimeBehavior=convertToNull&dontTrackOpenResources=true&tinyInt1isBit=false&defaultFetchSize=10000&useCursorFetch=true&autoReconnect=true&failOverReadOnly=false&useSSL=false" \
--driver com.mysql.jdbc.Driver \
--username ${mysql_user} \
--password ${mysql_password} \
--hcatalog-database test \
--hcatalog-table table \
--hcatalog-partition-keys 分区字段 \
--hcatalog-partition-values 分区字段值 \
--query 'select tt.* from (select @rowNum:=@rowNum+1 as INC_ID, t.* from table t,(select @rowNum:=0) b ) tt where $CONDITIONS' \
-boundary-query "select 1 as min , sum(1) as max from table " \
-m 8 \
--split-by INC_ID
  • solutionB: 使用另一个均匀索引-index2
    用时:8分钟
    sqoop import \
    --connect "jdbc:mysql://${mysql_host}:${mysql_port}/${mysql_db}?zeroDateTimeBehavior=convertToNull&dontTrackOpenResources=true&tinyInt1isBit=false&defaultFetchSize=10000&useCursorFetch=true&autoReconnect=true&failOverReadOnly=false&useSSL=false" \
    --driver com.mysql.jdbc.Driver \
    --username ${mysql_user} \
    --password ${mysql_password} \
    --table ${mysql_table} \
    --columns 'field1,field2,...,fieldn' \
    --hcatalog-database test \
    --hcatalog-table ${hive_table} \
    --hcatalog-partition-keys 分区字段 \
    --hcatalog-partition-values 分区字段值 \
    -m 8 \
    --split-by index2
  • solutionB_update: 查看了planB的执行计划,发现是全表扫描,要通过force index(index) 强制执行索引扫描
    用时:3分钟
    sqoop import \
    --connect     --connect "jdbc:mysql://${mysql_host}:${mysql_port}/${mysql_db}?zeroDateTimeBehavior=convertToNull&dontTrackOpenResources=true&tinyInt1isBit=false&defaultFetchSize=10000&useCursorFetch=true&autoReconnect=true&failOverReadOnly=false&useSSL=false" \
    --driver com.mysql.jdbc.Driver \
    --username ${mysql_user} \
    --password ${mysql_password} \
    --hcatalog-database test \
    --hcatalog-table table \
    --hcatalog-partition-keys 分区字段 \
    --hcatalog-partition-values 分区字段值 \
    --query 'select field1,...,fieldn from table T  force index(index2) where $CONDITIONS' \
    -m 8 \
    --split-by index2

推荐排名:solutionB_update > solutionB > solutionA
适用场景:solutionB_update/solutionB 适用于mysql有均匀索引的情况。没有均匀索引的话,用solutionA。由于一天的数据量很大(1000w+),应该考虑增量更新的方式-canal 导入,但听说使用canal会比较麻烦,有待研究,目前先用这些方案。

参考资料:
Mysql查看执行计划
sqoop 并行抽取数据,同时解决数据倾斜
利用 force index优化sql语句性能
sqoop官网
Mysql查询结果带行号【带解析】

sqoop参数说明(来源官网):
sqoop数据倾斜解决实战
sqoop数据倾斜解决实战
翻译:

7.2.2。选择要导入的数据
Sqoop通常以表为中心导入数据。使用--table参数选择要导入的表。例如,--table employees。此参数还可以标识数据库中的视图或其他类似表的实体。
默认情况下,表中的所有列都被选中进行导入。导入的数据以其“自然顺序”写入HDFS;也就是说,包含列a、B和C的表会导致数据导入,例如:
A1、B1、C1
A2、B2、C2
...
您可以选择列的子集并使用--columns参数控制它们的顺序。这应该包括要导入的列的逗号分隔列表。例如:--列“name,employee_id,jobtitle”。
可以通过向import语句中添加sqlwhere子句来控制导入哪些行。默认情况下,Sqoop生成SELECT<column list>FROM<table name>的语句。您可以使用--WHERE参数将WHERE子句附加到它后面。例如:--其中“id>400”。只有id列的值大于400的行才会被导入。
默认情况下,sqoop将使用query select min(<split By>),max(<split By>)from<table name>来查找创建拆分的边界。在某些情况下,此查询不是最佳查询,因此可以使用--boundary query参数指定返回两个数值列的任意查询。
上一篇:Sqoop安装与使用


下一篇:sqoop和mysql之间导问题