MYSQL系列之 change buffer 和 redo log

探讨InnoDB存储引擎的WAL(Write-Ahead Logging)技术与Change Buffer机制,解析如何通过先写日志再写磁盘的方式及缓存更新操作来提升数据库更新性能,减少磁盘I/O消耗。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

读丁奇大佬课程笔记与思考 课程链接

WAL技术(Write-Ahead Logging) 先写日志,再写磁盘:

当有一条记录需要更新的时候,InnoDB 引擎就会先把记录写到 redo log(粉板)里面,并更新内存,这个时候更新就算完成了。同时,InnoDB 引擎会在适当的时候,将这个操作记录更新到磁盘里面,而这个更新往往是在系统比较空闲的时候做。
刚刚update的语句还在缓存中未持久化磁盘,此时select是直接读取内存

redo log

InnoDB的redo log固定大小,比如可配置一组四个文件,每个文件1G,有两个指针,write pos记录当前写位置,边写边后移,checkpoint记录当前更新到文件的位置。write pos追上checkpoint,表示满了,停下来进行部分保存。
有了redo log,InnoDB就可以保证即便数据库发生异常启动,之前的记录不会丢失,此能力叫 crash-safe

change buffer

当需要更新一个数据页时,如果数据页在内存中就直接更新,而如果这个数据页还没有在内存中的话,在不影响数据一致性的前提下,InnoDB 会将这些更新操作缓存在 change buffer 中,这样就不需要从磁盘中读入这个数据页了。在下次查询需要访问这个数据页的时候,将数据页读入内存,然后执行 change buffer 中与这个页有关的操作。通过这种方式就能保证这个数据逻辑的正确性。

注意:
1、唯一索引不会用到 change buffer,插入值时,会查询数据是否唯一,也就没有必要用change buffer,所以唯一索引一定意义上会影响性能(如果buffer pool上有数据)
2、适合写多读少的场景

插入一条数据的过程

插入一条数据: insert into t(id,k) values(id1,k1),(id2,k2);
假设当前 k 索引树的状态,查找到位置后,k1 所在的数据页在内存 (InnoDB buffer pool) 中,k2 所在的数据页不在内存中

在这里插入图片描述
分析这条更新语句,你会发现它涉及了四个部分:内存、redo log(ib_log_fileX)、 数据表空间(t.ibd)、系统表空间(ibdata1)。
这条更新语句做了如下的操作(按照图中的数字顺序):
1、Page 1 在内存中,直接更新内存。
2、Page 2 没有在内存中,就在内存的 change buffer 区域,记录下“我要往 Page 2 插入一行”这个信息。
3、将上述两个动作记入 redo log 中(图中 3 和 4)。
做完上面这些,事务就可以完成了。所以,你会看到,执行这条更新语句的成本很低,就是写了两处内存,然后写了一处磁盘(两次操作合在一起写了一次磁盘),而且还是顺序写的。

查询一条语句的过程

在这里插入图片描述
1、读 Page 1 的时候,直接从内存返回。WAL 之后如果读数据,是不是一定要读盘,是不是一定要从 redo log 里面把数据更新以后才可以返回?其实是不用的。你可以看一下图 3 的这个状态,虽然磁盘上还是之前的数据,但是这里直接从内存返回结果,结果是正确的。
2、要读 Page 2 的时候,需要把 Page 2 从磁盘读入内存中,然后应用 change buffer 里面的操作日志,生成一个正确的版本并返回结果。
可以看到,直到需要读 Page 2 的时候,这个数据页才会被读入内存。
所以,如果要简单地对比这两个机制在提升更新性能上的收益的话,redo log 主要节省的是随机写磁盘的 IO 消耗(转成顺序写),而 change buffer 主要节省的则是随机读磁盘的 IO 消耗。

<think>嗯,用户想了解MySQL中一条update语句的执行过程,特别是buffer pool中各组件如redo log、undo logchange buffer的交互。首先,我需要回忆一下MySQL的架构,特别是InnoDB存储引擎的部分。可能得从客户端发送SQL请求开始,到解析、优化、执行,再到存储引擎层面的处理。 然后重点在buffer pool。Buffer pool是内存中的一块区域,用来缓存数据索引。当执行update时,数据页如果不在buffer pool中,需要先从磁盘加载进来。这里可能需要提到change buffer,它用于缓存非唯一索引的更新,避免立即读磁盘,但用户的问题是关于update的,所以可能需要说明change buffer的应用场景。 redo log是用于崩溃恢复的,记录物理修改。undo log则是记录事务前的数据镜像,用于回滚MVCC。这两者在事务处理中很重要,需要详细解释它们如何协作。 具体步骤大概是:事务开始,生成undo log,修改数据页,记录redo log,写入change buffer(如果有涉及非唯一索引的更新),然后事务提交时redo log刷盘,undo log可能留在内存或刷盘。需要确保这些步骤正确,以及各组件之间的顺序依赖关系。 可能需要考虑是否有图,但用户希望最好有图,但作为文本回复,可能需要用文字描述结构或用ASCII图示意。例如,展示客户端、server层、InnoDB引擎层,buffer pool中的各个部分,redo log buffer,磁盘上的redo log文件,undo log段,change buffer的结构等。 还需要注意术语的准确性,比如redo log bufferredo log文件的区别,undo log存放在undo tablespace中,change bufferbuffer pool的一部分。另外,在更新数据时,先写undo log,再修改数据页,然后记录redo log。对于二级索引的更新,如果页不在内存,则使用change buffer,避免立即读入。 可能还需要提到脏页,即被修改但未刷回磁盘的数据页,由后台线程定期刷新。以及checkpoint机制,确保redo log的空间重用。 用户可能想了解整个流程的细节,比如两阶段提交,或者如何保证ACID特性,但问题主要是update的执行组件交互,所以需要围绕buffer pool中的各个组件展开,可能不需要深入事务管理的所有细节。 要确保逻辑清晰,步骤明确,分阶段说明:解析、执行引擎、InnoDB处理,数据加载到buffer pool,生成undo log,修改数据,记录redo log,处理索引更新(可能用change buffer),事务提交时的处理,redo刷盘,binlog的写入(如果涉及主从的话),但用户没有提到binlog,可能需要判断是否要包含。不过问题重点在buffer pool中的组件,可能不需要涉及binlog,除非与redo log的两阶段提交有关。 需要检查是否有遗漏的组件,比如doublewrite buffer,但用户的问题可能不涉及这个,所以可以忽略。主要关注redo、undo、change bufferbuffer pool的关系。 总结步骤可能如下: 1. 客户端发送update语句。 2. Server层解析、优化,生成执行计划。 3. InnoDB查找数据页,如果不在buffer pool,则从磁盘加载。 4. 生成undo log,用于回滚MVCC。 5. 修改buffer pool中的数据页,标记为脏页。 6. 写入redo logredo log buffer,记录数据页的修改。 7. 如果有二级索引的更新,并且索引页不在内存,将更改记录到change buffer。 8. 事务提交时,redo log buffer刷盘,确保持久性。 9. 后台线程将脏页刷回磁盘,可能根据checkpoint机制。 10. undo log在事务提交后,可能被purge线程清理。 在解释过程中,需要明确各个组件的交互顺序,比如先写undo,再改数据页,再写redo。同时,change buffer的使用场景过程。 可能需要指出,在步骤7中,如果索引页在buffer pool中,直接更新;否则使用change buffer。而change buffer的合并发生在索引页被读取到buffer pool时,或者后台线程定期合并。 关于图表,可以用文字描述各部分的连接,例如: Buffer Pool包含: - 数据页 - Change Buffer(用于非唯一索引的更新) - 其他结构如自适应哈希索引等 当更新发生时: 1. 数据页在Buffer Pool?是→修改;否→从磁盘加载到Buffer Pool。 2. 生成Undo Log,存入Undo Log段(在系统表空间或独立undo表空间)。 3. 修改数据页,记录Redo LogLog Buffer。 4. 若涉及二级索引,检查索引页是否在Buffer Pool: - 是→直接更新; - 否→将更新记录到Change Buffer。 5. 提交事务时,Redo Log Buffer刷入磁盘的Redo Log文件。 6. 之后,脏页由后台线程刷回磁盘,Change Buffer中的变更在相关页被访问时合并。 这样应该能覆盖用户的问题点。需要确保术语正确,流程合理,各组件的作用交互清晰。</think>以下是对 MySQL 中 `UPDATE` 语句执行过程的详细解释,重点围绕 Buffer Pool 及其组件的交互(文字示意图描述): --- ### **一、整体流程概览** 1. **客户端请求**:发送 `UPDATE` SQL 语句。 2. **Server 层处理**:解析、优化,生成执行计划。 3. **InnoDB 引擎层**:处理数据修改,与 Buffer Pool 交互。 4. **事务提交**:持久化修改(Redo Log 刷盘)。 5. **后台操作**:脏页刷盘、Change Buffer 合并等。 --- ### **二、Buffer Pool 核心组件交互** #### **1. 数据加载到 Buffer Pool** - 若目标数据页**不在 Buffer Pool**,则从磁盘加载到内存。 - 若数据页已存在,直接修改内存中的副本(称为**脏页**)。 #### **2. Undo Log 生成** - **作用**:记录修改前的数据镜像,用于事务回滚 MVCC(多版本并发控制)。 - **写入位置**:Undo Log 存储在系统表空间或独立的 Undo Tablespace 中。 - **流程**: 1. 事务开始时,生成 Undo Log 记录。 2. 修改数据前,将旧值写入 Undo Log。 #### **3. 修改数据页** - 直接更新 Buffer Pool 中的**数据页**,标记为脏页。 #### **4. Redo Log 记录** - **作用**:确保事务的持久性(物理日志,记录页修改)。 - **写入位置**:先写入 **Redo Log Buffer**(内存),事务提交时刷盘。 - **流程**: 1. 修改数据页后,生成 Redo Log 记录到 Redo Log Buffer。 2. 事务提交时,通过 `fsync` 将 Redo Log Buffer 写入磁盘的 Redo Log 文件。 #### **5. Change Buffer 处理(针对非唯一索引)** - **作用**:延迟非唯一索引的更新,避免立即加载索引页到内存。 - **写入条件**: - 仅适用于非唯一索引。 - 当索引页**不在 Buffer Pool** 时,将更新操作缓存到 Change Buffer。 - **合并时机**: - 后续读取该索引页到 Buffer Pool 时,合并 Change Buffer 中的修改。 - 后台线程定期合并。 --- ### **三、交互流程图(文字示意)** ```plaintext 客户端 │ ▼ Server 层(解析、优化) │ ▼ InnoDB 引擎层 ├─ 1. 检查数据页是否在 Buffer Pool? │ ├─ 否 → 从磁盘加载到 Buffer Pool │ └─ 是 → 直接修改 │ ├─ 2. 生成 Undo Log(记录旧值) │ ├─ 3. 修改 Buffer Pool 数据页(标记为脏页) │ ├─ 4. 记录 Redo LogRedo Log Buffer │ └─ 5. 处理索引更新: ├─ 唯一索引 → 直接更新(需加载索引页) └─ 非唯一索引 → 若页不在内存,写入 Change Buffer │ 事务提交时: ├─ Redo Log Buffer → 刷盘(fsync) └─ 返回客户端成功 │ 后台线程: ├─ 脏页刷盘(Checkpoint 机制) └─ Change Buffer 合并到磁盘索引页 ``` --- ### **四、关键组件协作总结** | 组件 | 作用 | 交互顺序 | |----------------|--------------------------------------|-------------------------| | **Buffer Pool**| 缓存数据页,加速读写 | 数据页加载、修改、标记脏页 | | **Undo Log** | 支持回滚 MVCC | 修改前记录旧值 | | **Redo Log** | 保证事务持久性 | 修改后记录新值,提交刷盘 | | **Change Buffer** | 优化非唯一索引更新 | 延迟索引页更新,异步合并 | --- ### **五、附加说明** 1. **脏页刷盘**:由后台线程通过 Checkpoint 机制将脏页写入磁盘。 2. **Change Buffer 合并**:发生在索引页被读取到 Buffer Pool 时,或后台线程异步处理。 3. **崩溃恢复**:通过 Redo Log 重放未刷盘的修改,通过 Undo Log 回滚未提交的事务。 通过上述流程,MySQL 在保证 ACID 的同时,利用内存优化(Buffer Pool)异步机制(Change Buffer)提升性能。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值