大sql文件需拆分再导入,因navicat“运行sql文件”功能会将整个文件读入内存、逐条执行并频繁触发索引更新与外键检查,导致卡死或“packet too large”错误。
为什么大sql文件必须拆分再导入
navicat 的“运行sql文件”功能对超大文件(>500mb)天然不友好:它会把整个文件读进内存、逐条切分 ; 执行、每条都触发索引更新和外键检查。哪怕你导出的是批量 insert into t values (),(),(),它也会拆成单行提交,导致事务频繁、日志刷盘压力大、max_allowed_packet 容易超限。实测 1.2gb 文件在未调优下可能卡死或报 packet too large 错误——这不是 navicat 故意拖慢,而是它的 gui 架构决定的处理逻辑。
用 split + sed 拆分 SQL 文件(Linux/macOS)
不要用文本编辑器手动切,容易破坏语句完整性。推荐用命令行按 INSERT 块拆分,保留每个块的原子性:
- 先确认文件编码:
file -i your_backup.sql,常见为utf-8或utf-8-with-bom - 提取所有
INSERT INTO语句块(含多行值),每块控制在 5–10MB 左右:awk '/^INSERT INTO/ {f=1; print > "part_" ++i ".sql"; next} f && /^;/ {f=0; close("part_" i ".sql"); next} f {print > "part_" i ".sql"} !f {print > "header.sql"}' your_backup.sql - 拆完后检查头文件
header.sql是否含CREATE DATABASE、USE、字符集设置等前置语句,这些要单独执行一次 - 确保每个
part_*.sql以;结尾,且不含跨行注释干扰(如/* ... */跨多行需提前清理)
Windows 下用 PowerShell 拆分并保留事务边界
PowerShell 更适合 Windows 用户,关键是避免在 VALUES (..., ..., ...) 中间切断:
- 用
Get-Content -Raw一次性读入,按INSERT INTO+ 后续非空行 +;组合切分 - 示例片段(保存为
split-sql.ps1):$content = Get-Content "full.sql" -Raw<br>$blocks = [regex]::Split($content, "(INSERT INTO[\s\S]*?;(?=\s*INSERT INTO|\z))")<br>for ($i = 0; $i -lt $blocks.Length; $i++) {<br> if ($blocks[$i] -match "INSERT INTO") {<br> Set-Content "part_$i.sql" $blocks[$i].Trim()<br> }<br>} - 注意:PowerShell 默认 UTF-16,导出时加
-Encoding UTF8,否则 Navicat 可能乱码 - 拆完用
Get-ChildItem part_*.sql | ForEach-Object { Get-Content $_.FullName | Measure-Object -Character }验证各文件大小是否均衡
拆分后在 Navicat 中分批执行的关键设置
拆只是第一步,执行时仍要绕过默认瓶颈:
- 对每个
part_*.sql,右键目标数据库 → “运行SQL文件”,**务必取消勾选“执行前验证SQL语法”**(否则解析耗时翻倍) - 勾选“忽略错误继续执行”,防止某条脏数据中断整个批次(如主键冲突、字段长度超限)
- 不要勾选“执行前显示SQL内容”,避免大文件渲染拖慢 UI;首次可临时启用查一两个文件确认结构
- 如果批次中含大量
INSERT,导入前在 Navicat 查询窗口手动执行:SET autocommit = 0;和SET unique_checks = 0;,导入完再设回1 - 更稳妥的做法是:先用命令行导入头文件和第一个 part:
mysql -u root -p your_db ,剩下用 Navicat 图形界面跑
拆分本身不难,难的是每一块都得保持语义完整、编码一致、事务可控——尤其当原始 SQL 含存储过程或触发器定义时,INSERT 块拆分法会失效,此时必须用 mysqldump --skip-extended-insert 重导或改用 pt-online-schema-change 类工具分片写入。











