单事务控制在500~1000行最稳,超1万行易触发锁等待、undo日志膨胀和主从延迟;需结合行宽、i/o能力及innodb_log_file_size动态调整,并关闭autocommit、设innodb_flush_log_at_trx_commit=2协同优化。

事务不能太大也不能太小——高并发写入下,单事务控制在 500~1000 行最稳,超 1 万行大概率触发锁等待、undo 日志膨胀和主从延迟。
为什么事务大小直接影响写入吞吐
InnoDB 的行锁不是免费的:事务越长,持有锁时间越久,其他并发事务等待概率越高;同时 undo log 持续增长,刷盘压力上升,还会拖慢 purge 线程。更隐蔽的是,大事务在 binlog 中是一整条 event,主从复制时无法并行回放,直接卡住从库同步节奏。
常见错误现象:SHOW ENGINE INNODB STATUS 里频繁出现 SEMAPHORES 等待、TRANSACTIONS 列表里大量 lock wait、从库 Seconds_Behind_Master 持续上涨。
- 单条 INSERT + autocommit=1 → 每次都刷 redo + binlog,吞吐被 I/O 卡死
- 一个事务塞 10 万行 → undo 日志暴涨、锁范围扩大、事务提交瞬间日志刷盘压力爆炸
- 事务中混入 SELECT FOR UPDATE 或复杂子查询 → 锁升级风险高,间隙锁范围不可控
怎么定“合适”的事务粒度
没有全局最优值,但有可落地的判断依据:看业务写入节奏、行平均大小、以及当前硬件 I/O 能力。SSD 上每秒能稳定处理约 300~500 次 fsync,据此反推事务提交频率更靠谱。
实操建议:
- 行宽 ≤ 1KB 时,单事务控制在 500~1000 行(对应约 0.5~1MB 数据量)
- 行宽 ≥ 4KB(如含 TEXT/BLOB),单事务缩到 100~200 行以内
- 用
innodb_log_file_size倒推上限:若设为 512MB,单事务写入不应长期超过 1/4(即 128MB),否则 checkpoint 频繁触发 - 监控
Innodb_os_log_written每秒增量,若持续 > 10MB/s,说明日志写入已成瓶颈,需拆小事务或调参
批量插入时事务边界怎么切
别依赖应用层“攒够 N 条再提交”,而要结合数据特征动态切分。尤其当写入流不均匀(比如突发流量+长尾低峰)时,固定计数容易在峰值卡死。
推荐做法:
- 用时间窗口兜底:例如“每 200ms 强制提交一次”,避免某批数据因网络抖动迟迟凑不满
- 按语句长度切:拼接
INSERT INTO t VALUES (),(),()时,单条 SQL 控制在max_allowed_packet的 70% 以内(默认 64MB → 建议 ≤ 45MB) - 遇到唯一键冲突高频段(如抢购场景),主动拆成更小事务,防止
INSERT ... ON DUPLICATE KEY UPDATE触发大面积 gap lock - 不要在一个事务里跨多个热点表操作,哪怕只是 INSERT + UPDATE,也优先拆开
容易被忽略的配套动作
只调事务大小不管其他,效果会打折扣。真正起效需要三件套协同:
- 必须关掉
autocommit,显式用BEGIN/COMMIT包裹,否则事务切分无效 -
innodb_flush_log_at_trx_commit至少设为2,否则每提交一次仍强制刷盘,事务再小也没用 - 配合
innodb_buffer_pool_size调大(建议物理内存 70%),避免事务过程中频繁刷脏页干扰写入流 - 如果用了
LOAD DATA INFILE,它本身隐含事务语义,但默认不走 InnoDB 缓冲池预热,需加SET SESSION innodb_lock_wait_timeout = 30防卡死
事务大小是杠杆支点,但压不下去的阻力往往藏在参数协同和语句结构里——比如一条 INSERT ... SELECT 看似批量,实际可能锁全表;又比如 ON DUPLICATE KEY UPDATE 在并发下自动变成“锁一行、查一遍、更新或插入”,根本不是原子操作。这些细节比行数阈值更关键。











