load data infile 比单条 insert 快5–20倍,因其跳过sql层直接写入引擎;需文件位于服务端、路径绝对、匹配secure_file_priv、字段与行格式严格一致,并配合禁用索引、关闭外键/唯一校验、调大缓冲池等优化。

用 LOAD DATA INFILE 替代 INSERT 语句
单条 INSERT 插入万级数据时,网络往返、SQL 解析、事务开销会严重拖慢速度。而 LOAD DATA INFILE 是 MySQL 原生批量加载机制,跳过大部分 SQL 层处理,直接解析文本写入引擎层,实测快 5–20 倍。
关键点:
- 文件必须位于 MySQL 服务端(不是你本地),路径是服务端视角的绝对路径,如
/var/lib/mysql-files/data.csv - 需开启
secure_file_priv对应目录,查看命令:SHOW VARIABLES LIKE 'secure_file_priv'; - 字段分隔符、行结束符要与文件严格一致,例如 CSV 常用:
FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n' - 若表有主键/唯一索引,
LOAD DATA INFILE默认不跳过冲突,加IGNORE或用REPLACE控制行为
关闭自动提交 + 手动控制事务边界
默认每条 INSERT 都是一次独立事务,频繁刷盘导致 I/O 瓶颈。即使不用 LOAD DATA INFILE,也应显式合并写入批次。
操作建议:
- 执行前设
SET autocommit = 0;,插入完成后COMMIT; - 每批控制在 1000–10000 行之间(取决于单行大小和内存),太小起不到合并效果,太大可能触发锁等待或回滚日志溢出
- 避免在事务中混杂
SELECT或其他 DML,尤其是长事务下容易阻塞 MVCC 清理 - MyISAM 引擎不支持事务,此优化仅适用于 InnoDB
导入前临时调整表结构与配置
有些“保护性”设置在批量写入时反而成为性能枷锁,可阶段性关闭:
- 禁用非必要索引:
ALTER TABLE t DROP INDEX idx_xxx;,导入完成再重建。注意:主键和外键约束不能删,但外键检查可临时关:SET FOREIGN_KEY_CHECKS = 0; - 关掉唯一性校验(仅限确认数据无冲突时):
SET UNIQUE_CHECKS = 0;,否则每行都要查唯一索引 - 增大
innodb_log_file_size和innodb_buffer_pool_size(需重启生效),但线上调优需谨慎评估内存压力 - 如果源数据已按主键排序,且表是 InnoDB,导入前
ORDER BY主键能显著减少页分裂
避免使用 ORM 或通用工具做大批量导入
像 Django 的 bulk_create()、Spring Data JPA 的 saveAll() 或 phpMyAdmin 等界面工具,底层仍是拼接多条 INSERT 或分批提交,封装层带来额外序列化、连接复用、结果集处理开销。
更高效的做法:
- 用原生客户端命令行直连:
mysql -u user -p db_name (适合纯 SQL 文件) - 用
mysqlimport工具,本质是LOAD DATA INFILE的封装,支持并发、压缩文件(--compress)、字段映射等 - Python 可用
pymysql或mysql-connector-python的executemany(),但务必配合autocommit=False和合理 batch_size - 注意字符集:确保文件编码(如 UTF8MB4)与连接、表定义一致,否则出现乱码或截断,错误信息类似
Incorrect string value: '\xF0\x9F\x98\x80'...
真正卡住效率的,往往不是磁盘或 CPU,而是事务粒度、索引维护和客户端协议开销。批量导入不是“越快越好”,而是“在可控范围内压榨存储引擎的吞吐能力”。临时关索引、调参数可以,但别忘了恢复;用 LOAD DATA INFILE 要确认文件位置和权限——这两点漏掉,脚本跑十遍都报错。











