mysql离线迁移断点续传唯一可行方案是mydumper+myloader --resume,因其依赖表级独立sql文件及metadata位点实现续传,而mysqldump流式输出无切分无位点,重跑必全量重导且易主键冲突。

MySQL离线迁移本身不依赖网络,“网络中断”其实是误判——真正挂掉的是SSH会话、终端断连或本地磁盘I/O。能真正落地断点续传的,只有mydumper + myloader --resume这一对组合。
为什么 mysqldump 不支持断点续传
它输出是单一流式SQL,没有表级切分,也没有位点标记。--single-transaction只保证导出起点的一致性快照,不记录“已导到哪张表第几行”。重跑就是全量重导,重复导入必然触发Duplicate entry或主键冲突。
- 云数据库(如阿里云RDS)可能因缺失
REPLICATION CLIENT权限直接报错,连快照都拿不到 - 中断后无法定位卡在哪——目标库没表?有表但空?有数据但不全?全靠猜
- 管道导入(
mysqldump | mysql)更危险:gzip卡住、mysql客户端超时都会静默失败
myloader --resume 的实际工作逻辑
myloader --resume不是智能判断“差多少”,而是粗暴检查:information_schema.tables.table_rows > 0。只要目标表存在且行数非零,就跳过——不管数据是否完整、是否来自同一快照。
- 必须用
mydumper导出,不能用mysqldump;否则没有metadata文件,--resume无依据可依 - 导出时加
--chunk-filesize=64,防止单表SQL过大导致导入中途OOM或超时 - 目标库要提前建好同名库,但绝不能手动建表——
myloader需要自己建表并判断是否跳过 -
--resume不校验数据完整性,也不感知文件损坏。若db1/t1.sql最后少个括号,它仍会跳过这张表
中断后怎么准确定位卡点表
别看日志,直接比行数。源库和目标库两端的table_rows一对照,差得最明显的那张表就是断点。
- 执行这条命令扫目标库所有表当前行数:
ls /backup/db1/*.sql | sed 's/\.sql$//' | xargs -I{} mysql -h dst -Nse "SELECT COUNT(*) FROM db1.{}" - 再查源库:
SELECT table_name, table_rows FROM information_schema.tables WHERE table_schema = 'db1' ORDER BY table_name - 常见现象:
Skipping table t1 (non-empty)日志出现,但目标表行数只有源库的1/3——说明--resume误判了,必须删表重导 - 如果某张表
COUNT(*)非零,但SELECT * FROM t1 LIMIT 1报ERROR 2013,基本是SQL文件截断,数据已损坏
大表分片才是真正的细粒度断点
当单表超100GB,mydumper也扛不住时,就得放弃“全库快照”思路,改用主键范围分片——每个分片都是独立快照,断点就是上一个成功分片的最大id。
- 前提:表必须有单调递增、无空洞的整型主键(比如
id),否则BETWEEN切片会漏或重 - 导出命令示例:
mysqldump -u user -p -h src db1 table1 --where="id BETWEEN 100000 AND 199999" > table1_100k-199k.sql - 每个分片导出后,记录最大
id到progress.log,中断后从WHERE id > 199999继续 - 注意:
mysqldump --where不保证事务一致性,大表分片迁移期间必须停写或配合--single-transaction(但会锁表)
真正容易被忽略的点是:--resume只看行数,不看数据质量;分片迁移不看位点,只看主键连续性。断点本身不难找,难的是确认那个“点”之后的数据到底有没有残缺。











