MySQL 更新(UPDATE)语句的执行流程,包括 存储引擎内部的文件写入 和 主从复制的同步过程
一、MySQL 执行 UPDATE 的整体流程
假设我们执行:
UPDATE user SET name = 'Tom' WHERE id = 1;1. 客户端发送 SQL 到 MySQL Server
- 客户端通过 连接器(Connection)发送 SQL。
- MySQL Server 层接收到 SQL,进入 查询缓存(8.0 已废弃) 检查是否有缓存结果(更新语句一般不会命中缓存)。
2. 解析与优化
- 解析器(Parser):将 SQL 转换成语法树。
- 优化器(Optimizer):选择最优的执行计划(比如用哪个索引)。
- 执行器(Executor):调用存储引擎接口执行更新。
3. InnoDB 存储引擎执行更新
假设表使用 InnoDB 引擎,更新流程如下:
3.1 查找数据页
- 根据索引定位到对应的 数据页(Data Page)。
- 如果数据页不在 Buffer Pool(内存缓存区),则从 数据文件(.ibd 或共享 ibdata) 读取到 Buffer Pool。
3.2 加锁
- 对匹配的记录加 行锁(Record Lock)或 间隙锁(Gap Lock),保证事务隔离。
3.3 修改内存数据
- 在 Buffer Pool 中修改记录的值(name改为'Tom')。
- 记录到 Undo Log(回滚日志),用于事务回滚和 MVCC。
3.4 写入 Redo Log
- 将修改操作记录到 Redo Log Buffer(内存)。
- Redo Log 是物理日志,记录“在哪个数据页做了什么修改”。
- Redo Log Buffer 会周期性或事务提交时刷盘到 redo log 文件(ib_logfile0/ib_logfile1)。
3.5 写入 Binlog
- MySQL Server 层生成 Binlog(逻辑日志),记录 SQL 或行级变更。
- Binlog 先写到 Binlog Cache(内存),事务提交时刷盘到 binlog 文件(mysql-bin.xxxx)。
二、事务提交阶段
MySQL 使用 两阶段提交(2PC) 保证 Binlog 和 Redo Log 一致性:
- 阶段 1:写 Redo Log 并标记为 prepare状态(刷盘)。
- 阶段 2:写 Binlog(刷盘),然后将 Redo Log 标记为 commit状态。
这样保证:
- 如果写 Binlog 失败,Redo Log 也不会提交(事务回滚)。
- 如果写 Binlog 成功但崩溃,恢复时可用 Redo Log 重做。
三、主从复制流程
假设 MySQL 开启了 主从复制(基于 Binlog):
1. 主库写 Binlog
- 主库事务提交时,Binlog 文件中追加一条更新记录。
2. 从库 I/O 线程拉取 Binlog
- 从库的 I/O 线程 连接主库,读取新的 Binlog 内容。
- 将 Binlog 写入从库的 Relay Log(中继日志)。
3. 从库 SQL 线程执行 Relay Log
- 从库的 SQL 线程 读取 Relay Log,按顺序执行更新。
- 执行过程和主库一样:更新 Buffer Pool → 写 Redo Log → 写 Binlog(如果从库也开启 Binlog)。
四、涉及的文件写入顺序
我帮你整理成一个表格,方便你快速记忆:
| 阶段 | 文件/缓存 | 作用 | 
|---|---|---|
| 查找数据 | .ibd/ibdata数据文件 | 存储表数据页 | 
| 修改内存 | Buffer Pool | 内存缓存数据页 | 
| 记录回滚信息 | Undo Log(内存+磁盘) | 支持事务回滚和 MVCC | 
| 记录物理变更 | Redo Log Buffer → ib_logfile0/1 | 崩溃恢复 | 
| 记录逻辑变更 | Binlog Cache → mysql-bin.xxxx | 主从复制、数据恢复 | 
| 从库同步 | Relay Log | 从库中继日志 | 
| 从库执行 | Buffer Pool / Redo Log / Binlog | 与主库相同的执行流程 | 
五、完整执行顺序图
客户端 → MySQL Server → 解析器 → 优化器 → 执行器↓ InnoDB:1. 查找数据页(Buffer Pool / 数据文件)2. 加锁3. 修改内存数据4. 写 Undo Log5. 写 Redo Log Buffer↓ 事务提交:6. Redo Log prepare → 刷盘7. 写 Binlog Cache → 刷盘8. Redo Log commit↓ 主从复制:9. 主库 Binlog → 从库 I/O 线程 → Relay Log10. 从库 SQL 线程执行 Relay Log
=========================================================================
MySQL 中 Buffer Pool、Undo Log、Redo Log、Binlog、Relay Log 的作用和记录内容
1. Buffer Pool
- 作用:InnoDB 的内存缓存区,用于缓存数据页和索引页,减少磁盘 I/O。
- 记录内容:- 已读取的数据页(例如表数据、索引数据)
- 修改后的数据页(脏页,等待刷盘)
 
- 举例:
 当你执行SELECT * FROM user WHERE id=1时,InnoDB 会先从 Buffer Pool 查找数据页,如果没有则从磁盘读取并缓存到 Buffer Pool,下次查询同样数据时直接从内存读取。
2. Undo Log
- 作用:回滚日志,用于事务回滚和 MVCC(多版本并发控制)。
- 记录内容:- 修改前的旧数据(逻辑记录)
 
- 举例:
 执行UPDATE user SET age=30 WHERE id=1时,Undo Log 会记录id=1的原始age=25。如果事务回滚,就用 Undo Log 恢复成age=25。
3. Redo Log
- 作用:重做日志,保证事务的持久性(崩溃恢复)。
- 记录内容:- 数据页的物理修改(页号、偏移量、修改内容)
 
- 举例:
 执行UPDATE user SET age=30 WHERE id=1时,Redo Log 会记录该数据页的物理变化,即“第 X 页的某个偏移位置改为 30”。即使 MySQL 崩溃,重启后也能用 Redo Log 恢复到事务提交后的状态。
4. Binlog
- 作用:二进制日志,用于主从复制、数据恢复。
- 记录内容:- SQL 语句或行变更事件(逻辑记录)
 
- 举例:
 执行UPDATE user SET age=30 WHERE id=1后,Binlog 会记录这条更新语句或对应的行变更事件,主库会将 Binlog 发送给从库,从库执行同样的更新,实现数据同步。
5. Relay Log
- 作用:中继日志,用于 MySQL 主从复制的从库端。
- 记录内容:- 从主库接收到的 Binlog 内容
 
- 举例:
 从库接收到主库的 Binlog(例如UPDATE user SET age=30 WHERE id=1),会先写入 Relay Log,然后由 SQL 线程读取 Relay Log 并在从库执行更新。
| 组件名称 | 作用 | 记录内容 | 举例说明 | 
|---|---|---|---|
| Buffer Pool | 缓存数据页和索引页,减少磁盘 I/O | 已读取的数据页、修改后的脏页 | 查询 id=1时,数据页先从 Buffer Pool 读取 | 
| Undo Log | 回滚事务、实现 MVCC | 修改前的旧数据(逻辑记录) | 更新 age=30时记录原值age=25 | 
| Redo Log | 崩溃恢复,保证持久性 | 数据页的物理修改 | 记录“第 X 页某偏移改为 30” | 
| Binlog | 主从复制、数据恢复 | SQL 语句或行变更事件 | 记录 UPDATE user SET age=30 WHERE id=1 | 
| Relay Log | 从库执行主库变更 | 主库 Binlog 内容 | 从库接收 Binlog 写入 Relay Log 再执行 | 
Redo Log 和 Binlog
1. 记录内容的区别
- Redo Log - 记录的是物理层面的数据页修改(页号、偏移量、修改的字节内容)
- 属于 InnoDB 引擎专用,只描述“数据页如何被改动”
- 不能直接用来还原 SQL 语句,只能用来恢复数据页到某个状态
- 例子:页号=1234, 偏移=56, 原值=25, 新值=30 表示某个数据页的某个位置从 25 改成了 30。
 
- Binlog - 记录的是逻辑层面的变更(SQL 语句或行变更事件)
- 属于 MySQL Server 层,所有存储引擎都可以使用
- 可以用来重放 SQL,实现主从复制或数据恢复
- 例子:UPDATE user SET age=30 WHERE id=1; 或者记录成行事件:id=1, age=30
 
2. 作用的区别
- Redo Log:保证事务的持久性(崩溃恢复),让已提交事务在宕机后仍能恢复。
- Binlog:用于数据复制和归档,可以在不同 MySQL 实例之间同步数据,也可以用来做时间点恢复。
3. 存储方式的区别
| 特性 | Redo Log | Binlog | 
|---|---|---|
| 层级 | InnoDB 引擎层 | MySQL Server 层 | 
| 内容类型 | 物理日志(页修改) | 逻辑日志(SQL 或行事件) | 
| 用途 | 崩溃恢复 | 主从复制、数据恢复 | 
| 是否循环写 | 是(固定大小循环写) | 否(追加写,文件滚动) | 
| 是否所有引擎可用 | 否(仅 InnoDB) | 是(所有引擎) | 
✅ 总结:
Redo Log 是 “怎么改数据页”,Binlog 是 “改了什么数据”。
它们配合使用才能实现 事务的持久性 和 数据的可复制性。
