myloader --resume 在文件损坏时不可靠,因其仅判断目标表是否存在且非空,不校验.ibd文件完整性或sql文件有效性;若源表导出的.sql含截断或乱码,myloader会错误跳过,导致数据残缺却无提示。

直接说结论:数据文件损坏时,myloader --resume 会失效甚至跳过损坏表,必须先修复或绕过损坏点,再谈续传。
为什么 myloader --resume 在文件损坏时不可靠
myloader --resume 只检查目标库中表是否存在且非空,不验证 .ibd 文件是否可读、页是否校验通过。如果迁移中途源库某张表的 .ibd 已损坏(比如磁盘坏道导致导出的 SQL 文件含非法字节或 INSERT 语句截断),myloader 仍会跳过该表——它认为“表已存在”,但实际数据是残缺或乱码的。
常见现象包括:
- 目标库
SELECT COUNT(*) FROM t1返回非零值,但SELECT * FROM t1 LIMIT 1报错ERROR 2013: Lost connection -
myloader日志显示Skipping table t1 (non-empty),但后续pt-table-checksum校验失败 - 导入后应用查询返回
Incorrect key file或字段值为NULL(实为页解析失败)
损坏发生后必须做的三件事
别急着重跑 myloader。先停写、判损、隔离:
- 立即在源库执行
FLUSH TABLES WITH READ LOCK,防止损坏扩散 - 检查源备份目录下对应表的
.sql文件:用head -n 50 db1/t1.sql | tail -n 10看最后几行是否为完整INSERT;用file db1/t1.sql确认是否为 ASCII 文本而非二进制乱码 - 对比该表在源库的
information_schema.tables.table_rows和目标库当前行数;若目标库行数远少于源库,说明导入中断在中间,且--resume已误判
损坏表的两种务实处理路径
取决于损坏程度和业务容忍度:
- 若仅单张小表损坏(如日志表),且有近期
mysqldump备份:删掉目标库该表,去掉--resume参数,单独重导mysql -h dst -u user -p db1 - 若大表
.ibd损坏(如源库磁盘故障),无法重建.sql:改用Percona Data Recovery Tool for InnoDB解析原.ibd,导出为 CSV 再导入;注意该工具需匹配 MySQL 版本,且输出无事务保证,必须人工核对主键范围
切记:任何绕过损坏点的操作,都必须在重试前用 pt-table-checksum 对全库做一次校验,不能只依赖行数匹配。
真正容易被忽略的细节
很多人以为只要 myloader --resume 跑完就万事大吉。实际上,损坏常藏在边界处:比如某张表导出时刚好卡在 INSERT ... VALUES (...),(...), 的逗号后断开,生成的 SQL 文件语法不合法,但 myloader 仍会尝试执行并报错退出——而这个错误可能被日志轮转覆盖,下次重试时因表已存在又被跳过。所以每次迁移前,必须用 grep -l "INSERT INTO" db1/*.sql | xargs -I{} sh -c 'tail -n 1 {} | grep -q ");$" || echo "broken: {}"' 扫一遍 SQL 文件完整性。











