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 |
批量提交,提升效率 |
导出过程:
- Sqoop 把导出任务拆成 Map 任务
- 每个 Map 从 HDFS 读数据,通过 JDBC 批量写 MySQL
- 写完后提交事务
导出场景一:全量覆盖
场景:每天把 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 可以加
--direct走mysqlimport加速