redo log 在事务执行过程中、对数据页做物理修改前就写入 redo log buffer,再由刷盘策略控制落盘;关键触发点包括事务提交(innodb_flush_log_at_trx_commit=1)、log buffer 满、log_writer/log_flusher 后台线程定期刷盘。

MySQL 执行 SQL 时 redo log 是什么时候写入的
redo log 不是在 SQL 执行完才写,也不是在事务提交(COMMIT)那一刻“一次性”写入。它是在事务执行过程中、对数据页(buffer pool 中的 page)做**物理修改前**,就先将该修改操作记入 redo log buffer;随后由后台线程或刷盘策略控制,异步或同步地刷入磁盘上的 ib_logfile* 文件。
redo log 写入的关键触发点有哪些
实际写入磁盘不是靠“SQL 执行完毕”,而是依赖以下几种机制协同作用:
-
innodb_flush_log_at_trx_commit = 1(默认):每次事务提交时,强制调用fsync()将 redo log buffer 刷入磁盘,保证 crash-safe -
innodb_log_buffer_size满了:log buffer 占用达到阈值,自动触发刷盘 - 后台线程
log_writer和log_flusher定期(约每秒)检查并刷入未落盘日志 - 脏页刷新(
page cleaner)不直接触发 redo 写入,但若此时 log buffer 已有对应 LSN 的日志未刷盘,会阻塞刷脏页
redo log 和 SQL 执行顺序的真实关系
以一条 UPDATE t SET a=2 WHERE id=1 为例,关键步骤顺序如下(简化版):
1. 解析 SQL,获取行锁(record lock) 2. 在 buffer pool 中定位/读取 page(若不在内存则从磁盘加载) 3. 修改 page 中的记录(此时 page 变为“脏页”) 4. 生成对应的 redo 日志条目(如 MLOG_REC_UPDATE_IN_PLACE),写入 redo log buffer 5. 记录当前 LSN 到 page header(mtr_commit 阶段完成) 6. 事务进入 COMMIT 流程 → 根据 innodb_flush_log_at_trx_commit 决定是否 fsync
注意:步骤 4 发生在 步骤 3 后、步骤 5 前,且是逻辑上“原子”的 mini-transaction(mtr)提交环节,不是靠用户 SQL 语句结束来驱动。
容易被误解的几个点
很多人以为 “SQL 执行完 → redo 写入 → commit 成功”,其实中间夹着 mtr 提交和 log buffer 管理逻辑,容易踩坑的地方包括:
- 设置
innodb_flush_log_at_trx_commit = 0或2时,commit 返回成功 ≠ redo 已落盘,crash 可能丢事务 - 长事务持续修改大量数据,可能反复填满 log buffer,引发频繁刷盘,拖慢性能
- 使用
INSERT ... SELECT或大事务批量更新时,即使没显式 commit,log buffer 也可能因 size 溢出而提前刷盘,导致磁盘 I/O 比预期高 - MySQL 8.0+ 引入了独立的
log_writer线程,不再依赖主线程同步 write/fsync,但fsync仍可能成为瓶颈(尤其在机械盘或低配云盘上)
真正影响 redo 落盘时机的,从来不是 SQL 文本执行到哪一行,而是 mtr 生命周期、log buffer 状态、以及那几个关键的 InnoDB 配置项。忽略这点,光看 binlog 或 slow log 很难定位 I/O 突增或 crash 恢复异常的问题。










