一条MySQL更新语句的执行过程是什么样的?
3 个回答
理解一切,没有对错,让花成花,让树成树。诺尔莎当执行一条更新语句时,比如 `update T set c=c+1 where ID=2;`,MySQL 的执行流程中涉及了多个重要模块。 ### 执行流程 1. **连接器** - MySQL 首先通过连接器验证客户端的身份和权限,并建立连接。 2. **查询缓存** - 因为是更新语句,所以相关的查询缓存会被标记为无效。查询缓存被废弃的原因是数据发生更新后缓存的查询结果可能已经不再有效。 3. **分析器** - 分析器对 SQL 语句进行词法和语法解析,确认这是一个 `UPDATE` 操作,识别出目标表 `T` 和更新条件 `where ID=2`。 4. **优化器** - 优化器决定选择哪个索引或扫描方式,这里它会选择使用主键 `ID` 来定位需要更新的行。 5. **执行器** - 执行器根据优化器生成的执行计划,找到表 `T` 中 `ID=2` 的这一行数据,准备进行更新操作。这里重点是日志生成过程的时机。 ### 日志生成过程详解 #### 1. 生成 `undo log` - **时机**:在执行更新操作之前,MySQL 会首先生成 `undo log`。 - **作用**:`undo log` 用于记录当前数据的**旧版本**,即 `ID=2` 这一行的更新前的状态。这样做是为了支持事务回滚以及 MVCC 多版本并发控制。 - **示例**:假设 `ID=2` 这一行的字段 `c` 当前值为 `10`,`undo log` 会记录 `ID=2, c=10`,以便回滚时能够恢复原始值。 #### 2. 生成 `redo log` - **时机**:在生成 `undo log` 之后,执行器会将数据的修改操作记录到 `redo log` 中。 - **作用**:`redo log` 用于保证数据的持久性(crash-safe),即使系统崩溃,凭借 `redo log` 也能恢复未写入磁盘的数据。 - **示例**:在 `update T set c=c+1` 中,MySQL 并不会立即将修改后的数据写入磁盘,而是先写入 `redo log`,例如 `ID=2, c=11`。 #### 3. 记录 `binlog` - **时机**:`redo log` 生成后,MySQL 会生成并写入 `binlog`。`binlog` 记录了数据库的逻辑操作,用于主从复制和数据恢复。 - **作用**:`binlog` 是 MySQL 的逻辑日志,保存了数据库变更的记录,主要用于数据恢复和复制。`binlog` 会记录类似于 `update T set c=c+1 where ID=2;` 这样的逻辑操作。 - **示例**:`binlog` 会以逻辑格式保存 SQL 语句,便于在从库中重放或在主库中恢复。 #### 4. 两阶段提交 - **时机**:为了保证 `redo log` 和 `binlog` 之间的一致性,MySQL 使用了两阶段提交机制: 1. 首先将 `redo log` 记录标记为“准备”状态。 2. 接着写入 `binlog`。 3. 最后将 `redo log` 标记为“提交”状态。 - **作用**:通过这种机制,MySQL 保证了即使在事务提交过程中发生崩溃,也能在恢复时保持 `redo log` 和 `binlog` 的一致性。 ### 总结 在 `update` 语句的执行过程中,`undo log`、`redo log` 和 `binlog` 的生成时机和作用如下: - **undo log**:在更新操作之前生成,记录更新前的数据快照,支持事务回滚和 MVCC。 - **redo log**:在 `undo log` 生成后记录,保证系统崩溃后的数据恢复,属于物理日志。 - **binlog**:在 `redo log` 生成后写入,记录 SQL 语句的逻辑操作,主要用于主从复制和数据恢复。 这套机制确保了更新语句执行的安全性、数据一致性以及支持复杂的事务操作。编辑于 2024-01-02 01:45 •IP属地 美国举报评论收藏
我疯狂地奔跑,只想为你承担一切的伤害,我竖起了山丘,不愿你看见我丑陋的脸庞。许立国InnoDB 处理 `UPDATE` 语句时,涉及多个关键组件,包括: - **Buffer Pool**(缓存池) - **Undo Log**(回滚日志) - **Redo Log**(重做日志) - **Binlog**(二进制日志) - **磁盘存储** 完整的一次 `UPDATE` 事务操作流程如下: ### **1. 在 Buffer Pool 中读取数据** - **查询数据页是否已在 Buffer Pool 中**: - 若**存在**,直接使用。 - 若**不存在**,则**从磁盘加载该页**到 Buffer Pool。 ### **2. 记录 Undo Log(回滚日志)** - **在修改数据之前**,先记录**修改前的值**到 `Undo Log`。 - `Undo Log` **保证事务的原子性**,用于回滚操作。 - `Undo Log` **先写入内存**,然后由后台线程**定期刷新到磁盘**。 ### **3. 在 Buffer Pool 中更新数据** - **执行 `UPDATE` 语句**,直接**修改 Buffer Pool 中的数据页**(**内存更新**)。 - **数据页被标记为**`脏页(Dirty Page)`,意味着数据被修改但尚未写入磁盘。 ### **4. 记录 Redo Log(重做日志)** - **修改 Buffer Pool 数据的同时**,**将变更记录写入 `Redo Log Buffer`**。 - `Redo Log` 用于**保证崩溃恢复(崩溃后可重做变更)**,确保数据库的**持久性**。 ### **5. 提交事务** - 事务执行完后,**InnoDB 进入提交阶段**。 ### **6. 两阶段提交** **为了保证 `Redo Log` 和 `Binlog` 之间的数据一致性,采用两阶段提交。** #### **(1)写入 `Redo Log`(prepare 阶段)** - **先将 `Redo Log` 持久化到磁盘(`prepare` 阶段)**,保证数据变更可以恢复。 - 此时,事务**尚未真正提交**。 #### **(2)写入 `Binlog`(提交事务)** - **将 `Binlog` 记录写入磁盘**(事务提交日志)。 - **事务提交成功后**,更新 `Redo Log` 状态为 `commit`。 📌 **两阶段提交流程:** ```text 1️⃣ 事务执行 → 记录 Redo Log(prepare) → 持久化 Redo Log(阶段 1) 2️⃣ 记录 Binlog(阶段 2)→ 提交事务(更新 Redo Log 为 commit) ``` - **保证 MySQL 主从复制的一致性**(`Binlog` 先写入,主库才能正确同步到从库)。 - **如果 `Binlog` 写入失败,`Redo Log` 不会提交,保证事务完整性。** ### **7. 将 Buffer Pool 的脏页异步写入磁盘** - **事务提交后,数据仍在 Buffer Pool(缓存中)**,并未立即写入磁盘。 - **MySQL 通过后台线程**定期**将脏页刷盘**(**Checkpoint 机制**)。 - **此过程异步执行**,避免影响前台查询性能。 ### **8. 事务完成** - `UPDATE` 事务结束,数据变更被持久化。 ## **事务完整流程总结** | **步骤** | **操作** | **作用** | |---------|---------|---------| | **1. 读取数据** | 从 **Buffer Pool** 或 **磁盘** 读取数据页 | 确保可以进行 `UPDATE` | | **2. 记录 `Undo Log`** | 记录**修改前的值** | **支持事务回滚** | | **3. 更新 `Buffer Pool`** | 在**内存**中修改数据 | **提高查询性能** | | **4. 记录 `Redo Log`** | 记录修改操作到 `Redo Log Buffer` | **支持崩溃恢复** | | **5. 事务提交(两阶段提交)** | `prepare` 阶段 → 写 `Binlog` → `commit` 阶段 | **保证数据一致性** | | **6. 刷新 `Buffer Pool` 到磁盘** | **异步**写入磁盘 | **减少磁盘 I/O**,提高性能 | | **7. 事务完成** | 释放事务资源 | 确保系统正常运行 | 📌 **MySQL 通过 `Buffer Pool`、`Redo Log`、`Undo Log` 和 `Binlog` 共同保证事务的原子性、持久性和一致性。** 🚀发布于 2023-08-25 04:05 •IP属地 湖北举报评论收藏
不必太张扬,是花自然香。ketty ### 1.连接验证及解析 客户端与MySQL Server建立连接,发送语句给MySQL Server,接收到后如果是查询语句会先去查询缓存中看,有的话就直接返回了,(新版本的MySQL已经废除了查询缓存,命中率太低了),如果是缓存没有或者是非查询语句,会创建一个解析树,然后进行优化,(解析器知道语句是要执行什么,会评估使用各种索引的代价,然后去使用索引,以及调节表的连接顺序)然后调用innodb引擎的接口来执行语句。 ### 2.写undo log innodb 引擎首先开启事务,获得一个事务ID(是一直递增的),根据执行的语句生成一个反向的语句,(如果是INSERT会生成一条DELETE语句,如果UPDATE语句就会生成一个UPDATE成旧数据的语句),用于提交失败后回滚,将这条反向语句写入undo log,得到回滚指针,并且更新这个数据行的回滚指针和事务id。(事务提交后,Undo log并不能立马被删除,而是放入待清理的链表,由purge 线程判断是否有其他事务在使用undo 段中表的上一个事务之前的版本信息,决定是否可以清理undo log的日志空间,简单的说就是看之前的事务是否提交成功,这个事务及之前的事务都提交成功了,这部分undo log才能删除。) ### 3.从索引中查找数据 根据索引去B+树中找到这一行数据(如果是普通索引,查到不符合条件的索引,会把所有数据查找出来,唯一性索引查到第一个数据就可以了) ### 4.更新数据 判断数据页是否在内存中? 4.1数据页在内存中 索引是普通索引还是唯一性索引? 4.1.1普通索引 直接更新内存中的数据页 4.1.2 唯一性索引 判断更新后是否会数据冲突(不能破坏索引的唯一性),不会的话就更新内存中的数据页。 4.2 数据页不在内存中 索引是普通索引还是唯一性索引? 4.2.1普通索引 将对数据页的更新操作记录到change buffer,暂时不更新到磁盘。change buffer会在空闲时异步更新到磁盘。 4.2.2 唯一性索引 因为需要保证更新后的唯一性,所以不能延迟更新,必须把数据页从磁盘加载到内存,然后判断更新后是否会数据冲突,不会的话就更新数据页。 ### 5.写redo log(prepare状态) 将对数据页的更改写入到redo log,此时redo log中这条事务的状态为prepare状态。 ### 6.写bin log(同时将redo log设置为commit状态) 通知MySQL server已经更新操作写入到redo log 了,随时可以提交,将执行的SQL写入到bin log日志,将redo log 中这条事务的状态改成commit状态,事务提交成功。发布于 2022-02-08 21:14 •IP属地 云南举报评论收藏
公众号进入网站体验更佳

