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(事务真正提交)
      ↓
释放锁 → 后台刷脏页
相关推荐
火山上的企鹅1 小时前
Codex实战:APP远程升级服务搭建(三)后台管理页面(APK 上传、版本管理、多应用页签)
服务器·网络·数据库·oracle·qgc
阿狸猿2 小时前
论 NoSQL 数据库技术及其应用
数据库·nosql
FBI HackerHarry浩2 小时前
DataGrip2023.2.3默认保存的数据库和.sql文件在哪里?怎么修改默认路径?
数据库
袁小皮皮不皮2 小时前
3.HCIP OSPF补充知识(优化版)
服务器·网络·数据库·网络协议·智能路由器
运筹vivo@2 小时前
Python ContextVar 底层机制与内存模型拆解
前端·数据库·python
志栋智能3 小时前
超自动化巡检:知识沉淀与团队协作的新载体
大数据·运维·网络·数据库·人工智能·自动化
syt_biancheng3 小时前
Redis初识
数据库·redis·缓存
cmes_love4 小时前
股票逐笔level2历史行情下载十档订单薄五档tick分钟下载分享
数据库·区块链
仙俊红4 小时前
SQL 调优需要掌握的知识
数据库·sql
fofantasy4 小时前
NSK LH12AN 微型导轨技术手册
运维·网络·数据库·经验分享·规格说明书