Sqoop从HDFS导出至MySQL未导出全部记录的技术咨询
解决Sqoop导出HDFS数据到MySQL时记录缺失的问题
看起来你在Sqoop导出数据到MySQL的过程中遇到了记录不完整的问题,咱们一步步拆解原因并找到针对性的解决方案:
1. 先搞懂--update-mode allowinsert的实际行为
你用了--update-key job_title(指定主键)加上--update-mode allowinsert,Sqoop的处理逻辑是这样的:
- 遍历HDFS里的每条记录,先去MySQL表中查有没有相同
job_title的主键记录 - 如果已有这条主键:更新对应的
success_rate和petition_count字段 - 如果没有这条主键:插入这条新记录
而你去掉--update-mode allowinsert后,Sqoop默认用updateonly模式——这个模式只更新已存在的记录,完全不会插入新数据,所以空表执行后没记录是正常的,不用慌。
2. 排查296条变227条的核心原因
结合你的场景,大概率是下面几种情况导致记录缺失:
情况1:部分主键在MySQL中已存在
如果你的h1bfinal表在执行导出前就有数据,那HDFS里和现有主键重复的记录会被更新而非插入,最终表的总记录数不会加上这部分重复的数量。
- 验证方法:
- 先查MySQL当前的记录数:
SELECT COUNT(*) FROM h1bfinal; - 对比HDFS和MySQL的主键重复数:
# 先把MySQL的job_title导出到本地 mysql -u root -p'abcd' -D h1b2 -e "SELECT job_title FROM h1bfinal;" > mysql_jobs.txt # 统计HDFS中与MySQL重复的job_title数量 hadoop fs -cat /h1b/queries/pigqueries/Q_010/p* | awk -F'\t' '{print $1}' | grep -F -f mysql_jobs.txt | sort | uniq | wc -l
296-227=69,那说明这69条是被更新了,属于正常逻辑。 - 先查MySQL当前的记录数:
情况2:数据格式不兼容导致记录被静默跳过
你的MySQL字段有严格的类型限制,部分HDFS记录不符合要求的话,Sqoop会自动跳过这些记录(默认不会终止任务):
- 检查
job_title长度:job_title是varchar(50),如果HDFS里有超过50字符的标题,插入会失败:hadoop fs -cat /h1b/queries/pigqueries/Q_010/p* | awk -F'\t' '{if(length($1)>50) print "过长的job_title: "$1}' - 检查数值字段格式:
success_rate是decimal(5,2),petition_count是int,看看有没有非数值内容:# 检查success_rate是否为合法小数 hadoop fs -cat /h1b/queries/pigqueries/Q_010/p* | awk -F'\t' '{if($2 !~ /^[0-9]+\.[0-9]{2}$/) print "非法success_rate: "$0}' # 检查petition_count是否为合法整数 hadoop fs -cat /h1b/queries/pigqueries/Q_010/p* | awk -F'\t' '{if($3 !~ /^[0-9]+$/) print "非法petition_count: "$0}'
情况3:字段分隔符不匹配
你指定的是--input-fields-terminated-by ' '(制表符),但HDFS文件可能实际用了其他分隔符(比如空格、逗号),导致Sqoop解析字段错误,部分记录被判定为无效:
- 验证方法:随便看几条HDFS记录,确认分隔符是否为制表符:
hadoop fs -cat /h1b/queries/pigqueries/Q_010/p* | head -5
3. 针对性解决办法
- 如果是主键重复:这是
allowinsert模式的正常行为,要是想保留HDFS的最新数据,这个逻辑没问题;要是想强制插入所有记录(不推荐,毕竟主键唯一是约束),可以先清空MySQL表再导出。 - 如果是数据格式问题:要么修正HDFS里的非法数据(截断过长标题、调整数值格式),要么修改MySQL字段的类型/长度(比如把
job_title改成varchar(100))。 - 如果是分隔符不匹配:把Sqoop命令里的
--input-fields-terminated-by改成实际的分隔符就行。
4. 额外技巧:开启Sqoop详细日志
执行命令时加上-D sqoop.export.log.per.record=true,能打印每条记录的处理日志,直接看到哪些记录被跳过或失败:
sqoop export -D sqoop.export.log.per.record=true --connect jdbc:mysql://localhost/h1b2 --username root --password 'abcd' --table h1bfinal --export-dir /h1b/queries/pigqueries/Q_010/p* --update-mode allowinsert --update-key job_title --input-fields-terminated-by ' ';
内容的提问来源于stack exchange,提问作者Anand Raina




