← 每日面试题 学习看板

一次insert操作,MySQL的几种log的写入顺序?

面试题/03数据库中间件/01MySQL/06日志与数据一致性/一次insert操作,MySQL的几种log的写入顺序?.md

https://chat.deepseek.com/share/qqd90q46mjuo1u83z7

https://chat.deepseek.com/share/a9kmt38uvs96rx1dkp

面试记录 2026-10-13

题目:一次insert操作,MySQL的几种log的写入顺序?

难度:medium

标签:db/mysql/log, mysql/log, difficulty/medium

评分:⭐⭐☆☆☆(2/5)

我的回答

几种日志的写入顺序,首先会涉及事务,创建重试日志,也是 Redo log。Redo log 进行创建,然后进行提交,防止事务的事件出现服务器崩溃,用来做重试。然后创建 Undo log,Undo log 去确保整个事务进行,如果事务出现问题进行回滚。然后这些都完成,最终要写 binlog 用来进行数据同步。

点评

优点:

不足:

补充:

  1. SQL 解析到 Server 层,走语法/权限检查
  2. 生成执行计划,路由到 InnoDB
  3. InnoDB 生成 undo log(记录修改前状态,用于回滚)
  4. 修改 Buffer Pool 中的内存页(数据还未落盘)
  5. 写 redo log buffer(记录修改后状态)
  6. 事务提交时:先写 binlog buffer
  7. binlog write 到 binlog cache 文件(内存)
  8. binlog flush 到 OS 文件缓存(prepare 状态)
  9. 写 redo log buffer 并提交标记(redo log commit)
  10. redo log flush 到磁盘(fsync)→ binlog commit(fsync binlog 到磁盘)

完整讲解

第一部分:知识重点剖析

核心考点定位:理解 MySQL 三种日志的分工与两阶段提交协议,掌握事务提交时的完整执行链路。

知识点拆解:

  1. 三种日志的分工
  1. 一次 insert 的完整 10 步
  1. Server 层 SQL 解析、权限检查
  2. 生成执行计划,路由到 InnoDB
  3. InnoDB 生成 undo log(记录修改前)
  4. 修改 Buffer Pool 中的内存页(注意此时未落盘)
  5. 写 redo log buffer(记录修改后)
  1. 事务提交触发:写 binlog buffer
  2. binlog write → binlog cache(内存)
  3. binlog flush → OS 文件缓存,prepare 状态
  4. InnoDB 写 redo log commit 标记 → redo log commit → fsync 到磁盘
  5. binlog commit → fsync binlog 到磁盘
  1. 为什么需要 2PC
  1. 刷盘时机参数
  1. Undo Log 的持续存在与清理
  1. Redo Log 的循环写特性
  1. Binlog 的三种格式
  1. 常见事故场景

第二部分:考察方向与延伸递进

考察方向:

延伸递进面试题:

  1. 为什么 binlog 和 redo log 不能自己独立提交?
  1. innodb_flush_log_at_trx_commit=1 的性能开销有多大?
  1. undo tablespace 无限膨胀怎么排查?

第三部分:面试者参考回答(口语化)

面试官您好,我按"三种日志的分工 + 两阶段提交"来讲。

三种日志分工。redo log 是 InnoDB 内部的重做日志,记录修改后的状态,用于崩溃恢复;undo log 是 InnoDB 内部的回滚日志,记录修改前的状态,用于事务回滚和 MVCC;binlog 是 Server 层的日志,记录所有 DML/DDL 事件,用于主从复制和 PITR 时间点恢复。关键点:redo 和 undo 都在 InnoDB 内部,binlog 在 Server 层,跨层协调需要 2PC。

一次 insert 的完整顺序。第一步,SQL 到 Server 层解析、走执行计划。第二步,进入 InnoDB,先生成 undo log 记录修改前状态。第三步,改 Buffer Pool 里的内存页,注意此时未落盘。第四步,写 redo log buffer 记录修改后状态。第五步,事务提交时触发 2PC——先写 binlog buffer,然后 binlog write 到 binlog cache 文件,再 binlog flush 到 OS 文件缓存,此时 binlog 处于 prepare 状态。第六步,InnoDB 写 redo log 的 commit 标记并 fsync 到磁盘,这是 redo log commit。第七步,binlog 才真正 commit,fsync 到磁盘。

为什么需要 2PC。redo 和 binlog 各自独立落盘的话,会出现"redo 已 commit 但 binlog 未落盘"的中间态,崩溃后从库无法同步、PITR 也丢数据。2PC 保证两者原子——要么都成功要么都失败。崩溃恢复决策很简单:看 binlog 状态,prepare 就看 redo log 是否 commit,commit 就补写 binlog commit,未 commit 就回滚。

刷盘参数这块特别关键。innodb_flush_log_at_trx_commit 控制 redo,sync_binlog 控制 binlog,两个都设 1 就是双 1,最安全但性能最低。生产上金融、交易类坚持双 1;日志、埋点类可以放宽到 (1, 0) 或 (2, 1) 换性能。SSD 上单次 fsync 约 1ms,写入 IOPS 上限受 fsync 频率限制,所以 MySQL 用组提交(binlog group commit + redo group commit)合并 fsync,能提升 5-10 倍吞吐。

再补两个容易忽略的点。undo log 提交后不会立即清理,靠 Purge 线程异步清理,条件是没有活跃事务的 ReadView 使用它;一旦有个长事务持 ReadView,purge 就阻塞,undo tablespace 会膨胀到爆盘——这个坑我踩过,排查方法是 innodb_trx 找长事务,然后 kill 掉。redo log 是循环写的,默认两个 5GB,如果写入太快 checkpoint 跟不上,会强制 flush Buffer Pool 到磁盘,性能骤降,InnoDB: Log scan aborted 就是这个信号,需要调大 innodb_log_file_size。

当然,binlog 格式生产一律用 ROW 格式,避免 STATEMENT 里的 NOW()、UUID() 之类函数导致主从不一致。