autocommit=1下批量插入特别慢,是因为每条insert都触发完整事务流程(加锁→写redo log→强制刷盘→提交→释放锁),导致i/o与锁开销剧增,1000行即1000次磁盘写和锁操作。

因为默认自动提交(AUTOCOMMIT=1)会让每条 INSERT 都走完整事务流程,I/O 和锁开销翻 N 倍;手动事务把 N 次提交压缩成 1 次,性能通常能提 3–5 倍。
为什么 AUTOCOMMIT=1 下批量插入特别慢?
不是“插入慢”,是“每插一行都得刷一次日志、持一次锁、走一遍提交流程”。关键点:
-
innodb_flush_log_at_trx_commit=1(默认)时,每次COMMIT都触发log_flush到磁盘——1000 行 = 1000 次磁盘写 - 行锁或表锁的获取/释放也按行发生,高并发下锁竞争剧烈
- B+ 树索引更新无法合并,频繁分裂页,CPU 和 I/O 双高
- 即使只插 1 行,MySQL 也要解析 SQL、校验约束、写 undo log、写 redo log、刷盘、清理——全是固定开销
怎么安全地用 BEGIN/COMMIT 包裹批量插入?
别裸写 BEGIN 就完事,连接池和异常场景会直接翻车:
- 应用层必须先执行
SET autocommit = 0,否则某些驱动(如 JDBC、PDO)会在执行 DML 后隐式COMMIT -
BEGIN前确认SELECT @@autocommit返回 0,避免被中间件或连接池重置 - 每批数据执行完,必须显式
COMMIT或ROLLBACK;漏掉会导致下次复用该连接时卡在未提交事务里 - 不要在事务里混
SELECT、调用函数或触发器——它们会强制刷新脏页、拖慢事务执行,甚至让批量退化成串行
单次事务插多少行才合适?
没有万能数字,但超限会引发新问题:
- 推荐 1000~5000 行/事务:兼顾吞吐与稳定性,具体看单行大小(比如含大字段就往小了压)
- 超过 10 万行大概率触发
innodb_lock_wait_timeout或撑爆innodb_log_file_size,导致频繁 checkpoint,反而更慢 - 注意
max_allowed_packet限制:多值INSERT语句总长度不能超它(默认 64MB),否则报错Packet too large - 主从延迟敏感场景(如金融类业务),事务越长,从库回放延迟越明显,建议压到 2000 行以内
真正容易被忽略的,不是“要不要开事务”,而是“事务边界是否干净”——连接复用、异常路径的 ROLLBACK、驱动层对 autocommit 的干扰,任何一个没兜住,都会让性能优化变成线上事故的导火索。











