高效批量插入的核心是“一次通信、一次解析、一次提交”,需合并sql语句、事务提交和索引维护,辅以禁用约束、合理批次及load data infile等优化手段。

单条 INSERT 循环插入万级数据,基本等于在数据库门口排队等刷盘——性能瓶颈不在磁盘,而在交互和事务开销。真正高效的批量插入,核心是「一次通信、一次解析、一次提交」。
用多值 INSERT 合并语句,别写循环
这是最基础也最容易被忽略的优化点。每条独立的 INSERT INTO t (a,b) VALUES (1,2) 都要走完整网络往返 + SQL 解析 + 权限校验流程;而合并成一条:INSERT INTO t (a,b) VALUES (1,2), (3,4), (5,6),开销直接降为 1/N。
- 单条语句建议控制在
500–2000行之间:太少起不到合并效果,太多可能触发max_allowed_packet(默认 64MB),或让 MySQL 解析变慢 - 避免在
VALUES中嵌套函数(如NOW()、UUID()),否则无法复用预编译计划,也影响rewriteBatchedStatements=true的生效 - 如果字段含特殊字符或 NULL,确保参数绑定正确——用
?占位比拼字符串更安全
关闭 autocommit 并手动分批提交事务
MySQL 默认每条语句自动开启并提交事务,意味着每次插入都要刷一次 redo log。关掉它,把几百上千条插入包进一个事务里再 COMMIT,能省下 90% 的日志同步时间。
- Java JDBC 中调用
connection.setAutoCommit(false),最后connection.commit() - Python
pymysql或mysql-connector-python同样需显式conn.autocommit = False,再conn.commit() - 批次大小不是越大越好:单事务超
10 万行容易撑爆innodb_log_buffer_size或触发长事务锁等待;推荐5000–10000行/批
插入前临时禁用索引与外键检查
每插一行,InnoDB 就得更新所有二级索引的 B+ 树节点;唯一索引还要做重复值校验。对纯导入场景,这些检查全是冗余开销。
- 仅对
MyISAM表有效:ALTER TABLE t DISABLE KEYS→ 插入 →ALTER TABLE t ENABLE KEYS - InnoDB 不支持
DISABLE KEYS,但可临时关外键和唯一检查:SET FOREIGN_KEY_CHECKS = 0、SET UNIQUE_CHECKS = 0,完事后设回1 - 注意:此操作跳过约束校验,务必确保源数据本身合规,否则后续查不出问题数据
超大批量(百万级以上)优先用 LOAD DATA INFILE
当数据已存在本地文件(如 CSV),LOAD DATA INFILE 是性能天花板——它绕过 SQL 解析层,直接走存储引擎接口,速度通常是 INSERT 的 10–20 倍。
- 必须确保 MySQL 服务端能访问该文件路径(或使用
LOCAL关键字,需客户端和服务端都开启local_infile) - 执行前确认字段顺序、分隔符(
FIELDS TERMINATED BY ',')、换行符(LINES TERMINATED BY '\n')与文件实际一致 - 不支持表达式计算(如
CONCAT()),也不走触发器;若需清洗逻辑,得在导出文件前完成
真正卡住批量插入的,往往不是磁盘或 CPU,而是你没意识到 MySQL 正在为每一行重复做同一件事。合并语句、合并不提交、合并索引维护——这三个“合并”,才是压测时从 30 秒降到 3 秒的关键动作。细节如 rewriteBatchedStatements=true 参数是否启用、innodb_flush_log_at_trx_commit 是否调为 2,都得配合这三步才有意义。











