显式开启事务能显著提升INSERT速度,因MySQL默认autocommit=1,每条INSERT都触发完整事务流程(写redo log、刷盘、锁管理),而BEGIN/COMMIT将多行合并为一次持久化,大幅减少I/O与锁开销。

为什么显式开启事务能显著提升 INSERT 速度
因为 MySQL 默认是 AUTOCOMMIT=1,每条 INSERT 都会隐式启动一个独立事务、写 redo log、刷盘、再提交——这带来大量重复开销。显式用 START TRANSACTION + COMMIT 把多条 INSERT 包在一个事务里,就省去了中间的多次日志刷盘和锁释放/重建过程。
手动提交(BEGIN/COMMIT)vs 自动提交(AUTOCOMMIT=1)的关键差异
自动提交模式下,每个 INSERT 都是“原子小事务”,哪怕只插一行,也要走完整事务生命周期;而手动提交把 N 行合并为一次持久化动作。实测中插入 1 万行时,手动事务耗时通常只有自动提交的 1/5~1/3。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
-
AUTOCOMMIT=1:每行触发一次log_write+log_flush,磁盘 I/O 次数 = 行数 -
AUTOCOMMIT=0+ 手动COMMIT:N 行共用一次log_flush(取决于innodb_flush_log_at_trx_commit值) - 事务内索引更新延迟到
COMMIT前批量合并,避免 B+ 树反复分裂 - 表级锁或行锁的持有时间从“每行一次”变成“整个事务一次”,减少锁竞争
容易被忽略的陷阱:COMMIT 不是越晚越好
事务太长会导致 undo log 膨胀、主从延迟加剧、锁持有时间过久引发阻塞。尤其在高并发写入场景下,一个 10 万行的大事务可能卡住其他查询。
- 推荐单次事务控制在 1000~5000 行,具体看单行数据大小和服务器内存
- 避免在事务中混杂 SELECT 或调用函数——触发器、UDF、子查询都会拖慢事务执行
- 如果用了 Seata 等分布式事务框架,
@GlobalTransactional会让批量插入退化成 RPC 串行处理,耗时可能翻倍甚至超时 -
innodb_log_file_size太小会导致大事务频繁 checkpoint,反而降低吞吐
实际编码中怎么安全地用事务加速 INSERT
不要裸写 BEGIN; ... COMMIT;,尤其在应用层连接池环境下,得确保连接复用时不残留未提交事务。更稳妥的做法是:
- 用 ORM 的事务 API(如 MyBatis 的
@Transactional)而非原生 SQL 控制边界 - 批量前先设
SET autocommit = 0,但必须配对COMMIT或ROLLBACK,否则连接下次复用会卡在旧事务里 - 配合
INSERT INTO ... VALUES (...), (...), (...)多值语法,进一步减少解析与网络次数 - 插入前临时关掉非必要索引(
ALTER TABLE t DISABLE KEYS),导入完再ENABLE KEYS(仅 InnoDB 不支持,MyISAM 可用)
BEGIN 却忘了 COMMIT,或者在事务里查了大表,结果性能没提上去,锁倒是占了一堆。

















