一、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(回滚日志),用于事务回滚和 MV***。
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 标记为
***mit状态。
这样保证:
- 如果写 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(内存+磁盘) | 支持事务回滚和 MV*** |
| 记录物理变更 | 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 Log 5. 写 Redo Log Buffer ↓ 事务提交: 6. Redo Log prepare → 刷盘 7. 写 Binlog Cache → 刷盘 8. Redo Log ***mit ↓ 主从复制: 9. 主库 Binlog → 从库 I/O 线程 → Relay Log 10. 从库 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
- 作用:回滚日志,用于事务回滚和 MV***(多版本并发控制)。
-
记录内容:
- 修改前的旧数据(逻辑记录)
-
举例:
执行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 | 回滚事务、实现 MV*** | 修改前的旧数据(逻辑记录) | 更新 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 是 “改了什么数据”。
它们配合使用才能实现 事务的持久性 和 数据的可复制性。