sqoop导出

Sqoop 导出:从 HDFS 推回 MySQL,全量覆盖、增量更新,两种策略怎么选

Sqoop 导出,就是把 HDFS 上的数据写回关系型数据库。

HDFS(分析结果) → Sqoop Export → MySQL(业务系统查询)

什么时候需要导出?

  • Hive 算完报表,要推回 MySQL 供业务系统查询
  • 数据清洗后的结果,要写回业务库
  • 跨系统数据同步

导出前准备:目标表要先建好

Sqoop 导出不会自动建表,目标表必须在 MySQL 里提前建好。

CREATE TABLE staff (
  id INT PRIMARY KEY,
  name VARCHAR(50),
  age INT,
  sex TINYINT
);

关键: 表的字段数、顺序、类型必须跟 HDFS 数据对得上。对不上就报错。

基础导出:从 HDFS 到 MySQL

sqoop export \
  --connect jdbc:mysql://localhost:3306/company \
  --username root \
  --password 123456 \
  --table staff \
  --export-dir /user/hive/warehouse/staff_hive \
  --input-fields-terminated-by "\t" \
  --num-mappers 1 \
  --batch

关键参数:

参数 说明
--export-dir HDFS 数据目录(Hive 表对应的目录)
--table MySQL 目标表
--input-fields-terminated-by HDFS 文件的分隔符,必须跟数据一致
--num-mappers 并行度,默认 4,根据数据库负载调整
--batch 批量提交,提升效率

导出过程:

  1. Sqoop 把导出任务拆成 Map 任务
  2. 每个 Map 从 HDFS 读数据,通过 JDBC 批量写 MySQL
  3. 写完后提交事务

导出场景一:全量覆盖

场景:每天把 Hive 的完整报表结果推回 MySQL,替换前一天的数据。

做法: 导出前先清空 MySQL 表。

# 清空表(在 MySQL 里执行)
TRUNCATE TABLE staff;

# 再导出
sqoop export \
  --table staff \
  --export-dir /user/hive/warehouse/staff_hive \
  --input-fields-terminated-by "\t"

或者让 Sqoop 导出前先删数据(--delete-target-dir 不适合这里,那是 HDFS 的)——MySQL 侧需要手动 TRUNCATE 或用脚本先清。

导出场景二:增量更新

场景:每次只导新增或变化的数据,不覆盖已有数据。

做法:--update-key 指定唯一键,存在就更新,不存在就插入。

sqoop export \
  --table staff \
  --export-dir /user/sqoop/incremental_data \
  --input-fields-terminated-by "\t" \
  --update-key id \
  --update-mode allowinsert
参数 作用
--update-key id id 字段判断是更新还是插入
--update-mode allowinsert 存在则更新,不存在则插入

效果:

  • HDFS 里有 id=5 的数据 → MySQL 里更新这行
  • HDFS 里有 id=10 的数据,MySQL 没有 → 插入新行

从 Hive 导出:本质是读 HDFS

Hive 表的数据存在 HDFS 上,所以导出 Hive 表就是导出对应的 HDFS 目录。

-- 查看 Hive 表的 HDFS 路径
DESC FORMATTED staff_hive;
-- Location: hdfs://.../warehouse/staff_hive

注意: 如果 Hive 表是 Parquet/ORC 格式,Sqoop 不能直接读。需要先转成文本格式:

-- 建一个文本格式的临时表
CREATE TABLE staff_text ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS TEXTFILE AS
SELECT * FROM staff_orc;

-- 导出临时表
sqoop export --export-dir /warehouse/staff_text ...

常见问题

1. 数据类型不匹配

报错:Incorrect integer value: 'null' for column 'age'

Hive 里的 NULL 存的是 \N,MySQL 不认识。

解决: 告诉 Sqoop 怎么处理 NULL

sqoop export \
  --input-null-string '\\N' \
  --input-null-non-string '\\N' \
  ...

2. 字段数量对不上

报错:Column count doesn't match value count

HDFS 文件列数跟 MySQL 表列数不一样。

解决: 检查 HDFS 文件格式,或者在 MySQL 里调整表结构,或者导出前只选需要的列。

3. 导出中断,数据重复了

Sqoop 导出是批量提交的,中断后可能部分数据已写入。

全量场景: 先 TRUNCATE 表再导出,保证干净覆盖。

增量场景:--update-key + --update-mode allowinsert,重复执行不会产生重复数据(存在就更新)。

4. 导出太慢

  • --batch 批量提交
  • 调大 --num-mappers(注意数据库连接数)
  • MySQL 可以加 --directmysqlimport 加速