批量插入比单条插入快5–10倍,因开销被摊薄;建议每条INSERT含1000–5000行、关闭autocommit并分批提交;LOAD DATA INFILE更快2–3倍;ON DUPLICATE KEY UPDATE可避免竞态;调优innodb_log_file_size等参数至关重要。

批量插入比单条插入快一个数量级
MySQL 的 INSERT 单条执行时,每条语句都要走完整解析、优化、写 binlog、刷 redo log、更新索引等流程。换成批量插入后,这些开销被大幅摊薄。实际测试中,1000 行用 1 条 INSERT INTO t VALUES (...), (...), (...) 通常比 1000 条独立 INSERT 快 5–10 倍。
实操建议:
- 单条
INSERT语句最多塞 1000–5000 行(具体看行宽和max_allowed_packet设置) - 避免拼接超长 SQL 导致内存溢出或网络超时;可用
SHOW VARIABLES LIKE 'max_allowed_packet'查当前上限 - 如果数据来自文件,优先用
LOAD DATA INFILE,它跳过 SQL 解析层,速度通常是批量INSERT的 2–3 倍
关闭 autocommit + 手动事务控制是刚需
默认开启 autocommit=1 时,每条 INSERT 都是一次独立事务,强制刷盘(尤其是 innodb_flush_log_at_trx_commit=1 下),I/O 成为瓶颈。改成手动事务后,可把数百甚至数千条 INSERT 合并在一次提交里。
实操建议:
- 显式执行
SET autocommit = 0,再BEGIN,插完用COMMIT - 事务大小要平衡:太小(如每 10 行一提交)起不到优化效果;太大(如 10 万行一提交)可能触发锁升级、undo 日志膨胀、主从延迟加剧
- 若表有唯一索引,大事务失败回滚代价高,建议按 1000–5000 行分批提交
INSERT ... ON DUPLICATE KEY UPDATE 比先查后插更安全高效
业务中常见“存在则更新,不存在则插入”逻辑。如果用 SELECT 判断再决定 INSERT 或 UPDATE,会引发竞态(两个并发请求同时查到不存在,都执行 INSERT,其一报唯一键冲突)。而 INSERT ... ON DUPLICATE KEY UPDATE 是原子操作,且避免了额外查询开销。
实操建议:
- 必须确保表上有合适的
UNIQUE或PRIMARY KEY约束,否则该语法不生效 - 注意
ON DUPLICATE KEY UPDATE中的列值引用:用VALUES(col_name)拿 INSERT 子句里的值,不要直接写变量名 - 该语句仍会触发唯一索引查找,若冲突率极高(比如 90% 都要更新),不如直接用
REPLACE INTO(但注意它本质是删+插,会变更自增 ID 和影响外键)
InnoDB 配置项对写入性能影响极大
很多 MySQL 实例沿用默认配置,但 innodb_log_file_size、innodb_buffer_pool_size、innodb_flush_log_at_trx_commit 这几个参数不调优,写入性能基本被锁死。
实操建议:
-
innodb_log_file_size建议设为 1–2GB(总日志容量 = 文件数 × 单文件大小),太小会导致频繁 checkpoint,拖慢写入 -
innodb_buffer_pool_size至少设为物理内存的 50%–75%,减少磁盘随机读对写入路径的干扰 - 若允许短暂断电丢数据(如日志类场景),可设
innodb_flush_log_at_trx_commit = 2(每秒刷一次 log),写入吞吐能提升 3–5 倍;设为 0 更快但风险更高 - 调整这些参数需重启 MySQL,且修改
innodb_log_file_size前必须干净关闭服务,否则启动失败
真正卡住写入性能的,往往不是 SQL 写法本身,而是事务边界没控好、日志配置太保守、或者压根没意识到 LOAD DATA INFILE 的存在。调参不是玄学,但得结合磁盘类型(NVMe 还是 SATA)、业务一致性要求、主从同步压力一起看——漏掉任意一环,优化效果都会打折扣。











