直接重跑SQL文件会导致主键冲突,因脚本缺乏幂等性;Navicat不记录执行断点且“忽略错误”功能有限;可靠方案是拆分文件、添加标记、分段执行并验证。
导入中断后,直接重跑整个SQL文件会重复插入
navicat默认不记录已执行到哪一行,中断后若直接重试,insert into 语句会报主键冲突或唯一索引重复错误,而不是跳过已完成部分。这不是navicat的bug,而是sql脚本本身缺乏幂等性设计——它没做insert ignore、replace into或on duplicate key update处理。
用mysql命令行续传更可靠,但需提前准备
图形界面中断后状态难追踪,而命令行可配合mysql的--force和--skip-foreign-key-checks参数跳过错误继续执行,再结合tail -n +N file.sql(Linux/macOS)或more +N file.sql(Windows)定位断点行号。不过这要求你:
- 导出时就用
mysqldump --skip-extended-insert,让每条INSERT独立成行,方便按行切分 - 导入前先查出最后成功插入的自增ID或时间戳,人工估算中断位置
- 临时禁用外键检查:
SET FOREIGN_KEY_CHECKS = 0;,否则跨表依赖容易卡住
Navicat里“忽略错误继续执行”不是万能的
在“运行SQL文件”对话框中勾选忽略错误继续执行,只对语法错误或单条语句失败有效;如果中断发生在事务中间(比如COMMIT前崩溃),Navicat不会自动回滚未完成事务,后续重跑可能造成数据不一致。更麻烦的是:
- 该选项无法跳过已存在的主键值,仍会报
Duplicate entry - 大文件加载阶段若内存溢出,Navicat可能根本没开始执行,此时“忽略错误”毫无意义
- 日志里只显示最后几条错误,看不到中断前最后一条成功执行的语句
真正可控的恢复方式:拆分+标记+分段验证
不要指望一次导入完500MB的SQL文件。正确做法是:
- 用
split -l 10000 full.sql chunk_(Linux/macOS)或工具如SQLDumpSplitter把文件切成万行级小块 - 每段开头加
SELECT 'START chunk_001';,结尾加SELECT 'END chunk_001';,导入后查这些标记确认执行范围 - 对每个chunk单独启用
SET autocommit = 0;+COMMIT;,失败时只回滚当前段 - 导入后立刻用
SELECT COUNT(*) FROM table_name;核对行数,比肉眼扫日志靠谱得多
最易被忽略的一点:Navicat的“运行SQL文件”功能在中断后不会释放连接持有的元数据锁,有时得手动杀掉对应线程(KILL <code>PROCESSLIST中的ID),否则后续导入可能被挂起。











