mysql执行SQL时redo log在什么时候写入_日志执行顺序说明

9次阅读

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

mysql执行SQL时redo log在什么时候写入_日志执行顺序说明

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_writerlog_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 = 02 时,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 恢复异常的问题。

text=ZqhQzanResources