根本原因是内存、超时或SQL语句过长导致导入失败,应采用流式分片处理:用sed/Python按完整语句切分SQL文件,每片加SET autocommit=0;和COMMIT;,导入时调大--max-allowed-packet等参数并禁用约束检查。

备份文件太大,mysql 命令直接导入失败怎么办
根本原因不是“文件大”,而是客户端或服务端在导入时内存吃紧、超时、或单次 SQL 语句太长被截断。常见报错如:MySQL server has gone away、Packet for query is too large、或者导入中途卡死无响应。
解决思路是绕过一次性加载整个 SQL 文件,改用流式分片处理:
- 用
split按行数或大小切分 SQL 文件(推荐按;分割的完整语句,但split不懂语法,所以优先用sed或专用工具) - 确保每片以完整
INSERT或CREATE TABLE开头、以分号结尾,避免语句被截断 - 导入时加参数控制行为:
mysql -u root -p --max-allowed-packet=512M --net-buffer-length=1M db_name -
--max-allowed-packet必须同时在客户端和服务端配置(my.cnf中设max_allowed_packet = 512M),只改客户端无效
用 mysqlpump 替代 mysqldump 实现原生分片导出
mysqlpump 是 MySQL 5.7+ 自带的并行导出工具,支持按表、按库、甚至按行分片导出,比手动切分更安全可靠。
典型用法:
mysqlpump --user=root --password --databases mydb --tables users logs --chunk-size=100000 --compress-output=LZ4 > dump_chunked.sql
关键点:
-
--chunk-size控制每条INSERT包含多少行(不是字节数),适合大表;小表不会被拆 -
--compress-output减少传输体积,但导入前需先解压,不能直接 pipe 给mysql - 不支持
mysqldump的--single-transaction等部分参数,跨版本迁移前务必验证一致性 - 导出结果仍是单文件,但内部 INSERT 已按 chunk 组织,导入时更稳定
source 在 MySQL 客户端里无法分片执行大 SQL 文件
source 命令本质是客户端逐行读取并发送给服务端,它不解析 SQL 逻辑,遇到超长 INSERT 或注释块仍会触发 max_allowed_packet 错误。
真正可行的分片执行方式是:在 shell 层面把文件按语句拆开,再逐个 mysql -e 执行:
awk '/;/ {print $0 > "part_" ++i ".sql"; next} {print > "part_" i ".sql"}' full_dump.sql
但这个 awk 脚本对多行注释、引号内分号会误切——生产环境强烈建议用 sed -n '/^--/!{/;/p;}' 配合人工检查,或直接用 Python 写个简单解析器识别语句边界。
- 不要依赖
head -n 10000这类纯行数切割,极易切在INSERT ... VALUES (...,中间 - 每个分片开头加
SET autocommit=0;,结尾加COMMIT;,减少事务开销 - 导入前先
SET unique_checks=0; SET foreign_key_checks=0;,完事后恢复
导入后发现数据不全或主键冲突,怎么快速定位漏在哪一片
不是所有分片都同等重要:结构语句(CREATE TABLE)必须最先执行且只能执行一次;而数据语句(INSERT)可以重跑,但要注意去重。
排查步骤很实际:
- 用
grep -n "INSERT INTO \`users\`" part_*.sql | wc -l统计各片插入行数,和原始表SELECT COUNT(*) FROM users对比 - 检查每片末尾是否含
;,缺失会导致后续语句静默失败(MySQL 认为还在同一条语句里) - 导入时加
-v参数(mysql -v -u...),能看到每条语句执行结果,但日志量极大,建议配合2>&1 | grep -E "(error|Warning)" - 最稳妥的是导出时就加
--skip-triggers --skip-routines,避免存储过程或触发器干扰分片逻辑
真正麻烦的永远不是“怎么分”,而是分完之后没人校验每片是否语法合法、边界是否闭合、字符集是否一致——这些细节一旦出错,导入完成才发现少了几万行,就得重来。










