MySQL大文件导入应使用shell重定向而非source命令,因source逐行解析导致内存高、无并发、易中断;正确方式是mysql -u root -p --max_allowed_packet=1G target_db < large.sql,并优化SQL格式与分卷策略。

mysql 命令重定向导入比 source 快得多,且稳定;用错方式(比如在 MySQL 客户端里执行 source)是慢的根本原因,不是配置或硬件问题。
别用 source 导入大文件
source 是客户端逐行读取、解析、拼接再发送的机制,内存占用高、无并发、无法中断恢复。1GB 以上文件大概率卡死或报 ERROR 2013 (HY000): Lost connection to MySQL server during query 或 ERROR 1153 (08S01): Got a packet bigger than 'max_allowed_packet' bytes。它不是为批量导入设计的。
- 真正该用的命令是 shell 级重定向:
mysql -u root -p --max_allowed_packet=1G target_db < /path/to/large.sql - 必须显式指定库名
target_db,否则遇到INSERT INTO table就报ERROR 1046 (3D000): No database selected - 如果 SQL 文件含
CREATE DATABASE或USE,先手动建库并授权,或拆成两步:mysql -u root -p < create_db.sql && mysql -u root -p target_db < data.sql
关键参数必须每次导入都显式传
服务端参数只对当前连接生效,不传就用默认值(比如max_allowed_packet=4M),哪怕 my.cnf 里设了也没用。
- 加
--max_allowed_packet=1G防包截断 - 加
--net_read_timeout=3600 --net_write_timeout=3600防因 wait_timeout 中断 - 不要用
SET GLOBAL动态改,那会影响其他连接,且对已建立连接无效
SQL 文件本身要“能跑快”
命令和参数都对了,脚本写法差照样慢几倍。- 确保
INSERT是多值格式:INSERT INTO t VALUES (1,'a'),(2,'b'),(3,'c');,而不是每行一个INSERT - 导入前手动删掉开头的
SET NAMES utf8mb4类语句——它们在非交互式导入中常失效,改用连接参数--default-character-set=utf8mb4 - 若文件含
CREATE TABLE,确保显式写ENGINE=InnoDB,避免低版本默认用 MyISAM 导致锁表 - 在文件开头加
SET unique_checks=0; SET foreign_key_checks=0; SET autocommit=0;,结尾补COMMIT; SET unique_checks=1; SET foreign_key_checks=1;(前提是确认数据无主键/唯一键冲突)
分卷比硬扛更实际
2GB 文件出错就得重来;拆成 50MB/份后,失败只需重试其中一份。但不能用split -l 硬切——它不管语句边界,极易切坏 INSERT。
- 更稳妥的方式是按
INSERT块切:awk '/^INSERT INTO/{n++} {print > "chunk_" int((n-1)/100) ".sql"}' large.sql(每 100 个INSERT分一份) - 想看进度?装
pv:pv /path/to/big.sql | mysql -u root -p target_db(apt install pv或brew install pv)
真正卡住的地方,往往不是“没调参”,而是用了 source 这个错误入口,或者 SQL 文件里还混着几十万行单条 INSERT。优化得从命令和脚本结构开始,不是最后才想的事。


















