如何利用MySQL数据泵技术高效归档数据?
MySQL数据泵(mysqldump)不适合在线归档,因其锁表且影响性能,仅适用于冷备迁移。生产环境应使用pt-archiver、分区表或存储过程实现事务级删除与迁移,归档后需重建索引以维持查询性能。
很多人在做数据归档时会下意识想到 mysqlpump,但这里必须说清楚:它本质是逻辑备份工具,不是增量迁移或在线归档工具。它导出的只是全量快照(SELECT * FROM table 的结果),既无法按时间条件筛选,也不能边归档边删,更不支持事务级一致性控制。如果试图用它导出旧数据再手动导入归档库,会遇到三个硬伤:源表锁表风险高、时间范围难以精确控制、删除动作必须额外写脚本且容易丢数据。

mysqlpump 不适合直接做归档操作
直接拿 mysqlpump 做“归档”其实是个常见误区。它导出的只是某个时间点的快照,无法按时间条件筛选,不能边归档边删,也不支持事务级一致性控制。如果你非要用它来导出旧数据再手动导入归档库,至少会遇到三个硬伤:源表锁表风险高、时间范围难以精确控制、删除动作必须额外写脚本且极易丢数据。
真正能配合 mysqlpump 的归档场景只有冷备迁移
只有当归档目标是“彻底下线某个历史库”,并且业务允许停写时,mysqlpump 才有用武之地。举个例子:把 2022 年前的订单库整体迁移到归档实例,操作流程如下:
- 先停写源库,确保没有新数据写入
- 用
mysqlpump -u root -p --databases old_orders_db --no-create-db --skip-triggers > archive_2022.sql导出(加上--no-create-db避免建库冲突) - 目标库提前建好同名库,再用
mysql -u root -p old_orders_db < archive_2022.sql导入 - 验证
COUNT(*)和主键最大值是否一致,确认没有截断
需要注意:mysqlpump 默认不导出 CREATE DATABASE 语句,但会导出 USE db_name,所以目标库必须已存在且字符集匹配;如果原库有大量 BLOB 字段,建议加上 --compress-output=ZLIB 来减小传输体积。
想在线归档?得换工具或方案
生产环境要边查边归档、按 create_time 切片、控制每批 1000 行,mysqlpump 对此完全无能为力。可行的路径只有三条:
- 用
pt-archiver:支持--where "create_time < '2022-01-01'"+--limit 1000+--bulk-insert,自动分批、带错误重试、可指定目标库表 - 用分区表 +
ALTER TABLE ... DROP PARTITION:前提是建表时就按时间分区,归档只需 detach 整个分区,毫秒级完成 - 手写存储过程循环:用
INSERT INTO archive_db.t SELECT ... WHERE ... AND id BETWEEN AND+DELETE成对执行,但必须加START TRANSACTION包裹,且需要监控innodb_row_lock_waits
容易被忽略的是归档后的查询路径——归档表如果没建 INDEX(create_time),后续查某年订单反而比原表还慢;而 mysqlpump 导出的 SQL 文件里默认不含索引语句,导入后必须手动补上。
