mydumper + myloader 能将迁移速度提升至 mysqldump 的 8–12 倍,但必须规避自增主键冲突、gtid 兼容性、大表不分片和线程争抢四大关键问题;其中 --chunk-filesize=64 是硬性要求,避免大表生成超大 sql 文件导致 myloader oom 或解析卡死,配合 --threads=8 实现真正并行处理。

直接说结论:mydumper + myloader 能把迁移速度拉到 mysqldump 的 8–12 倍,但前提是必须绕开自增主键冲突、GTID 兼容性、大表分片和线程争抢这四个最常卡死的点。
mydumper 导出时为什么加 --chunk-filesize=64 是硬性要求
不设分块,mydumper 对大表(比如 >5GB)会生成单个超大 SQL 文件,myloader 导入时容易触发 OOM 或长时间卡在 parse 阶段。这不是性能问题,是内存模型限制——myloader 默认把整个 chunk 文件读进内存再解析执行。
-
--chunk-filesize=64表示按 64MB 切分数据文件,实际效果是每张大表被拆成多个table.00001.sql、table.00002.sql等独立文件 - 配合
--threads=8,每个线程可并行处理一个 chunk,真正压满 IO 和 CPU - 别用
-r 500000(按行分片),它依赖主键连续性;线上支付/订单类表主键常有空洞,会导致 chunk 不均、部分线程饿死 - 如果目标库是 MySQL 8.0+,导出时务必加
--no-binlogs --no-gtids,否则myloader会尝试还原 GTID set,报ERROR 1840 (HY000)
myloader 导入失败报 ERROR 1062 Duplicate entry 是表结构没清理干净
这个错误根本不是数据重复,而是 myloader 多线程 INSERT 同一张表的不同 chunk 时,触发了自增主键竞争。源库导出语句里带 AUTO_INCREMENT=123456789,而目标库建表后没重置计数器,导致两个线程同时从同一值开始分配 ID。
- 导入前必须清空目标库:用
myloader --drop-if-exists,别手写DROP DATABASE,会丢掉字符集和排序规则 - 导出时加
--no-schemas(已有结构)或--no-create-info(只导数据),避免建表语句覆盖自增起点 - 确认目标表
AUTO_INCREMENT值已重置:执行ALTER TABLE t AUTO_INCREMENT = 1,或者导入后手动SELECT MAX(id)+1 FROM t再ALTER - 导入命令必须显式指定线程数:
myloader --threads=8 --database=testdb,默认--threads=4在表少于 4 张时根本跑不满
跨 MySQL 版本迁移时 myloader 连不上 8.0+ 的静默失败怎么排查
旧版 myloader(v0.9.5 之前)不支持 MySQL 8.0 默认的 caching_sha2_password 插件,连接时日志只显示 Connected to MySQL server 就卡住,无报错、无超时、无退出。
- 先查
myloader --version,确保 ≥ v0.10.0;GitHub release 页面明确写了 “Add support for caching_sha2_password” - 目标库用户必须显式指定认证插件:
ALTER USER 'loader_user'@'%' IDENTIFIED WITH mysql_native_password BY 'xxx'; - 导出端如果是 MySQL 8.0+,除了
--no-binlogs --no-gtids,还要加--skip-triggers --skip-events,避免 8.0 新语法(如 event scheduler)被误导入到 5.7 - 验证连接是否真通:用
mysql -h target -u loader_user -p --default-auth=mysql_native_password手动连一次
真正决定迁移成败的,从来不是总耗时,而是那个你没注意到的 AUTO_INCREMENT 值、那条漏掉的 --no-gtids、或者那个以为“默认够用”的线程数。这些点不提前对齐,再快的工具也会在凌晨三点停在 ERROR 1062 上。











