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(事务真正提交)
      ↓
释放锁 → 后台刷脏页
相关推荐
三道渊18 分钟前
进程通信与网络协议
开发语言·数据库·php
徒 花22 分钟前
数据库知识复习05
android·数据库
豆沙糕23 分钟前
RAG文档切分最佳实践:企业级方案+主流策略+生产落地
数据库·人工智能
不会写DN25 分钟前
SQL 多表操作全解
数据库·sql
爱莉希雅&&&28 分钟前
linux中MySQL数据库备份恢复的四种方法(更新中)
linux·数据库·mysql·数据库备份·mysqldumper
云边有个稻草人36 分钟前
时序数据库选型技术剖析:从写入、存储到查询的五个关键维度
数据库
疯狂成瘾者42 分钟前
Chroma向量数据库
开发语言·数据库·c#
ayt0071 小时前
Netty AbstractNioChannel源码深度剖析:NIO Channel的抽象实现
java·数据库·网络协议·安全·nio
荒川之神1 小时前
Oracle 数据仓库星座模型(Galaxy Model)设计原则
数据库·数据仓库·oracle
杰克尼1 小时前
redis(day03-商户查询缓存)
数据库·redis·缓存