MySQL 中 UPDATE 语句的执行过程全解析

文章目录

  • 一、整体流程概述
  • [二、Server 层:解析 SQL → 调用 InnoDB 执行更新](#二、Server 层:解析 SQL → 调用 InnoDB 执行更新)
  • [三、InnoDB 查找记录(索引决定性能与锁)](#三、InnoDB 查找记录(索引决定性能与锁))
  • 四、加锁:保证事务隔离性
  • [五、写 Undo Log:记录旧值(用于 MVCC & 回滚)](#五、写 Undo Log:记录旧值(用于 MVCC & 回滚))
  • [六、修改 Buffer Pool(内存)的数据页](#六、修改 Buffer Pool(内存)的数据页)
  • [七、写 Redo Log(prepare 阶段)](#七、写 Redo Log(prepare 阶段))
  • [八、写 Binlog:用于主从复制与恢复](#八、写 Binlog:用于主从复制与恢复)
  • [九、两阶段提交:确保 Redo 和 Binlog 一致](#九、两阶段提交:确保 Redo 和 Binlog 一致)
  • [十、释放锁 & 后台刷脏页](#十、释放锁 & 后台刷脏页)
  • [十一、UPDATE 全流程总结](#十一、UPDATE 全流程总结)

一、整体流程概述

先给出一条 UPDATE 的"核心执行链路",便于你快速记住流程:

查找记录 → 加锁 → 写 undo → 修改内存页 → redo prepare → 写 binlog → redo commit → 释放锁

这条链路贯穿了 UPDATE 的所有关键机制,我们将按时间顺序深入讲解。
redolog与binlog为什么需要两阶段提交?
WAL(Write-Ahead Logging)机制详解:为什么数据库一定要"先写日志再写数据"?


二、Server 层:解析 SQL → 调用 InnoDB 执行更新

当客户端发送 SQL:

sql 复制代码
UPDATE user SET age = 20 WHERE id = 1;

MySQL Server 做的工作包括:

  1. 解析 SQL(Parser)
  2. 优化器生成执行计划(Optimizer)
  3. 执行器运行执行计划(Executor)

执行器最终会调用 InnoDB:

复制代码
handler->update_row()

真正的数据读写发生在 InnoDB,而 Server 层更多是调度者。


三、InnoDB 查找记录(索引决定性能与锁)

InnoDB 使用聚簇索引(B+Tree)查找目标行:

  • 如果 WHERE 使用了索引 → 快速定位
  • 如果没有索引 → 全表扫描,扫描过程中会导致大量锁竞争

找到记录后,数据页会被加载到 Buffer Pool(内存) 中。

这一步非常关键,因为:

  • 是否使用索引决定了扫描开销
  • 也决定了加锁范围(是否出现"锁表"效果)

四、加锁:保证事务隔离性

找到记录后,InnoDB 会加锁来保证并发事务的隔离性:

  • 使用唯一索引时:行锁(Record Lock)
  • 使用普通索引或无索引:Next-Key Lock(记录锁 + 间隙锁)

如果表没有索引,UPDATE 会扫描整个表:

可能会锁住大量记录,导致类似"表锁"的效果。

理解锁机制是排查 UPDATE 阻塞的关键。


五、写 Undo Log:记录旧值(用于 MVCC & 回滚)

在更新前,InnoDB 会生成 undo 记录:

text 复制代码
旧值:age = 18

Undo 的作用:

  • 事务回滚(恢复旧值)
  • MVCC 快照读(构建历史版本链)

Undo 属于逻辑日志,记录的是"如何还原到更新前"。


六、修改 Buffer Pool(内存)的数据页

InnoDB 在内存中对数据页进行实际修改:

text 复制代码
age = 20

此时发生了:

  • 数据页被标记为 脏页(Dirty Page)
  • 并未立即写回磁盘,刷盘由后台线程异步完成

此时 UPDATE 的"数据修改"已经发生,但事务还未正式提交。


七、写 Redo Log(prepare 阶段)

为了支持宕机恢复(Crash Recovery),InnoDB 会记录 redo:

复制代码
page_id=xxx, offset=xxx, new_value=20

Redo 写入流程:

  1. 写入 redo log buffer(内存)
  2. 刷盘到 redo log file
  3. 标记为 prepare

此时 redo 已经持久化,但事务还未提交,仍有回滚可能。


八、写 Binlog:用于主从复制与恢复

Server 层写入 binlog:

复制代码
update user set age=20 where id=1;

或 ROW 格式的事件。

Binlog 的关键作用:

  • 主从复制
  • 基于时间点恢复(PITR)

Binlog 也需要刷盘(fsync),否则可能造成主从不一致。


九、两阶段提交:确保 Redo 和 Binlog 一致

为了避免主库和从库数据不一致,MySQL 使用 Two Phase Commit(2PC)

阶段 1(prepare):

InnoDB 写 redo prepare(已持久化)

阶段 2(commit):

Server 写 binlog 成功后,通知 InnoDB:

复制代码
可以提交了

InnoDB 将 redo 从 prepare → commit。

至此:

  • redo 已提交
  • binlog 已落盘
  • 事务正式成功

这是 MySQL 保障一致性的核心机制。


十、释放锁 & 后台刷脏页

事务提交后:

  • 锁被释放,其他事务可以访问记录
  • 脏页由后台线程(checkpoint、page cleaner)异步刷盘

更新操作本身不会阻塞在磁盘 IO 上,这也是 MySQL 高性能的关键。


十一、UPDATE 全流程总结

复制代码
SQL 解析 → 执行器调用 InnoDB
      ↓
索引查找 → 加锁
      ↓
生成 undo(保存旧值)
      ↓
修改内存页(产生脏页)
      ↓
redo prepare(写 redo)
      ↓
写 binlog
      ↓
redo commit(事务真正提交)
      ↓
释放锁 → 后台刷脏页
相关推荐
做cv的小昊17 小时前
【TJU】信息检索与分析课程笔记和练习(7)数据库检索—Ei
数据库·笔记·学习·全文检索
zgl_2005377917 小时前
ZGLanguage 解析SQL数据血缘 之 标识提取SQL语句中的目标表
java·大数据·数据库·数据仓库·hadoop·sql·源代码管理
莳花微语17 小时前
记录一次OGG进程abended,报错OGG-01431、OGG-01003、OGG-01151、OGG-01296问题的处理
数据库·sql·mysql
尋有緣17 小时前
力扣1355-活动参与者
大数据·数据库·leetcode·oracle·数据库开发
萧曵 丶18 小时前
MySQL三大日志系统浅谈
数据库·sql·mysql
煎蛋学姐18 小时前
SSM校园兼职招聘系统x6u36(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·企业管理·ssm 框架·校园兼职招聘系统
ChineHe19 小时前
Redis基础篇004_Redis Pipeline流水线详解
数据库·redis·缓存
西柚补习生19 小时前
通用 PWM 原理基础教学
数据库·mongodb
小张程序人生19 小时前
ShardingJDBC读写分离详解与实战
数据库
木风小助理19 小时前
三大删除命令:MySQL 核心用法解析
数据库·oracle