InnoDB redo log大小应设为峰值写入量60秒的2–3倍(如7.2GB→8–10GB),过小致频繁checkpoint,过大延长安装恢复;长事务阻塞purge致undo膨胀;RC隔离级禁用间隙锁、RR默认加next-key锁;autocommit=0仅适用于强关联多语句事务。

InnoDB 的事务日志(redo log)大小怎么设才不拖慢写入
redo log 太小会导致频繁刷盘和 checkpoint 阻塞,太大会延长崩溃恢复时间。默认 innodb_log_file_size=48M(MySQL 5.6+ 是单文件大小,总容量为 innodb_log_files_in_group × innodb_log_file_size),对中高并发写入场景往往不够。
实操建议:
- 观察
SHOW ENGINE INNODB STATUS中的Log sequence number和Last checkpoint at差值,若每 10–20 秒就触发一次 checkpoint,说明日志空间吃紧 - 用
SELECT variable_value FROM performance_schema.global_status WHERE variable_name = 'Innodb_os_log_written'统计 60 秒内写入量,取峰值的 2–3 倍作为总 redo log 容量(例如峰值 120MB/s × 60s = 7.2GB → 总 log 设为 8–10GB) - 调整需停机:先
SET GLOBAL innodb_fast_shutdown = 0,再停 MySQL、重命名旧ib_logfile*、修改配置、重启 - 避免设单个文件 > 2GB(部分旧版本或文件系统有兼容问题)
长事务为什么让 MVCC 和 purge 线程雪崩
一个未提交的事务会把 read view 持有数分钟,导致 InnoDB 无法清理其前镜像(undo log),undo 表空间膨胀,purge 线程追不上,最终 history list length 持续飙升,查询变慢甚至卡住。
实操建议:
- 监控
SELECT TRX_ID, TRX_STARTED, TRX_STATE, TRX_QUERY FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(TIMEDIFF(NOW(), TRX_STARTED)) > 60,抓出超 60 秒的活跃事务 - 应用层必须设置
wait_timeout和interactive_timeout(建议 300–600 秒),并启用连接池的 idle timeout(如 HikariCP 的idleTimeout) - 禁止在事务里做 HTTP 调用、文件读写、sleep 等外部耗时操作;拆分大事务:比如批量更新 10 万行,改用每 1000 行 commit 一次
- 开启
innodb_print_all_deadlocks = ON,配合错误日志定位隐式事务陷阱(如 autocommit=0 + 忘记 commit)
READ COMMITTED 和 REPEATABLE READ 在锁行为上到底差在哪
很多人以为只是“是否能看到其他事务已提交的修改”,其实核心差异在**加锁范围与持续时间**,直接影响并发性能和死锁概率。
实操建议:
-
READ COMMITTED下:普通 SELECT 不加锁(快照读),UPDATE/DELETE 只锁匹配到的行(且每次语句执行都新建 read view),间隙锁(gap lock)被禁用 → 更适合高并发更新,但可能产生幻读 -
REPEATABLE READ下:UPDATE/DELETE 默认加 next-key lock(行锁 + 间隙锁),防止幻读;同一事务内多次 SELECT 共享 read view → 更强一致性,但锁范围大、易锁表 - 线上 OLTP 业务若能接受幻读(比如订单状态轮询类场景),可显式设
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED,配合innodb_locks_unsafe_for_binlog = OFF(MySQL 5.7+ 已移除,但逻辑等效) - 不要全局改隔离级别,优先在应用连接初始化时按需设置;用
SELECT @@transaction_isolation核查实际生效值
autocommit=0 + 显式 BEGIN 是不是真能提升性能
不能一概而论。关闭 autocommit 后手动控制事务边界,确实减少 commit 开销,但代价是锁持有时间拉长、undo 增长、连接资源占用更久——尤其在短平快的单条 INSERT/UPDATE 场景下,反而更慢。
实操建议:
- 仅当一组逻辑强关联的 DML(如“扣库存 + 写订单 + 记日志”)必须原子执行时,才用
BEGIN; ...; COMMIT; - 避免在存储过程中滥用
START TRANSACTION:函数内嵌事务会抑制语句级 binlog 记录,影响主从一致性 - 确认客户端驱动是否自动开启事务(如某些 JDBC 连接串带
autoReconnect=true时可能隐式重连并丢事务上下文) - 用
SHOW PROCESSLIST查看Command列为Sleep但Time很大的连接,大概率是应用没正确 close 或 commit 导致事务悬挂
ROW vs STATEMENT)、甚至磁盘 I/O 调度策略(deadline vs none),都会让同一个 innodb_log_file_size 在不同环境表现迥异。上线前务必在同规格压测环境跑真实业务流量,而不是只看 sysbench 结果。










