应拆分大事务、降级隔离级别、调整日志刷盘策略、监控长事务并优化业务逻辑。具体包括:每千行提交一次批量操作;读多写少场景改用read committed;设innodb_flush_log_at_trx_commit=2提升吞吐;定期查innodb_trx超时事务;应用层加锁等待超时控制。

事务粒度太大,导致锁等待和回滚开销高
长事务会持有锁时间过长,阻塞其他事务,同时 undo log 持续增长,影响 purge 线程效率。常见于把整个批量导入、报表生成或跨服务操作包在一个事务里。
- 拆分大事务:比如
INSERT INTO t VALUES (...)10 万行,改用每 1000 行提交一次,用循环控制COMMIT - 避免在事务中调用外部 HTTP 接口或文件读写,这些不可控延迟会直接拖长事务生命周期
- 确认是否真需要事务:只读查询、单行
UPDATE且无并发更新冲突场景,可考虑去掉BEGIN/COMMIT
隔离级别设为 REPEATABLE READ 却没用到 MVCC 优势
MySQL 默认的 REPEATABLE READ 在多数只读+少量更新场景下反而增加 gap lock 开销,尤其配合 SELECT ... FOR UPDATE 时容易引发死锁。
- 读多写少业务(如内容展示、后台查询)可降级为
READ COMMITTED,减少锁范围,提升并发 - 若必须用
REPEATABLE READ,确保 WHERE 条件走索引,否则会升级为表级锁或全范围 gap lock - 检查
innodb_lock_wait_timeout是否过短(默认 50 秒),超时后应用层重试逻辑不完善会导致雪崩式重试
频繁短事务 + 高并发触发 log_flush 瓶颈
每提交一次事务,InnoDB 默认刷一次 redolog(innodb_flush_log_at_trx_commit = 1),磁盘 I/O 成为瓶颈,尤其在 SSD 性能一般或日志盘负载高的机器上。
- 允许部分数据丢失风险时,可设
innodb_flush_log_at_trx_commit = 2(每秒刷一次 log),吞吐量通常提升 3–5 倍 - 若使用 RAID 或企业级 NVMe,且业务对 crash 安全性要求极高,保持
=1,但需确认innodb_log_file_size足够(建议 ≥ 512MB),避免频繁 checkpoint - 禁用
autocommit=0后手动控制事务边界,但忘记COMMIT会导致连接长期占用,务必配超时监控
未清理历史事务或长事务未被发现
长时间未提交的事务(如应用崩溃未 rollback、调试时中断连接)会卡住 purge 线程,导致 trx_rseg_history_len 持续上涨,最终拖慢所有 DML。
- 定期查
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(NOW()) - TIME_TO_SEC(TRX_STARTED) > 60,找出运行超 1 分钟的事务 - 启用
innodb_print_all_deadlocks = ON,结合 error log 分析死锁根因,而不是只看应用层报错 - 应用层加事务模板:用
SET SESSION innodb_lock_wait_timeout = 10限制单次锁等待,避免一个慢事务拖垮整条链路
事务优化不是调几个参数就能一劳永逸的事,真正难的是在业务逻辑里识别出“哪里真的需要事务”“哪里其实可以妥协”。很多性能问题根源不在 MySQL,而在代码里一个没关的 Connection 或一个没设 timeout 的 RPC 调用。











