真正卡住高并发批量插入的是默认日志刷盘策略+单批行数失控+忘记显式事务包裹三者叠加;需协同调整innodb_flush_log_at_trx_commit与sync_binlog,并控制每批100–500行、用BEGIN/COMMIT包裹。

为什么批量INSERT还是卡在高并发下
不是没批量,而是“伪批量”——比如用循环拼接 INSERT INTO t VALUES (1),(2) 但每条仍单独提交;或者单批塞了 5000 行,结果触发 max_allowed_packet 被截断,客户端静默失败。高并发时更致命的是日志刷盘策略没调:默认 innodb_flush_log_at_trx_commit=1 和 sync_binlog=1 让每次事务都强制 fsync,哪怕 SSD 也扛不住每秒上千次小事务的刷盘压力。
必须协同调整的两个核心配置
单独改其中一个基本无效,且必须确认业务能接受对应的数据一致性折衷:
-
innodb_flush_log_at_trx_commit=2:日志写入 OS 缓冲即返回,崩溃最多丢失 1 秒数据,写入吞吐常翻倍以上 -
sync_binlog=0或sync_binlog=1000:关闭 binlog 同步,或改为每 1000 次事务刷一次,主从延迟略增,但避免频繁fsync - 若用 MySQL 8.0+ 且开启
binlog_transaction_dependency_tracking=WRITESET,可进一步缓解主从延迟
每批多少行才不踩坑
100–500 行是实测收益最稳的区间,超过 500 行后性能提升明显放缓,反而容易触发限制或内存抖动:
- 单批控制在 1–2MB 内,避免超
max_allowed_packet(默认 64MB,但建议设为 32M 并在程序侧主动切分) - 字段越多、内容越长(如含 JSON、TEXT),单批行数要越少;纯整型主键 + 短字符串可放宽到 500 行
- 用显式事务包裹:先
BEGIN,再批量INSERT,最后COMMIT;别依赖autocommit=0后忘记COMMIT,否则锁一直挂着
比多值INSERT更快的替代方案
当数据已在服务端文件中,LOAD DATA INFILE 是真正的性能天花板,它绕过 SQL 解析层,直接构造记录进 buffer pool:
- 文件必须放在 MySQL 服务端本地,路径需符合
secure_file_priv限制(查SHOW VARIABLES LIKE 'secure_file_priv') - 语句末尾加
CHARACTER SET utf8mb4防中文乱码,且源文件编码必须一致 - 遇到唯一键冲突想跳过?加
IGNORE;想覆盖?用REPLACE,但注意后者是DELETE + INSERT,开销更大 - 如果文件在客户端,且无法启用
local_infile,就老实用多值INSERT+PreparedStatement.addBatch(),别硬上LOAD DATA


















