news 2026/8/13 22:31:46

MySQL-Innodb-内存结构

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MySQL-Innodb-内存结构

一、 Innodb内存结构的基本组成

1.1 基本结构说明

Innodb内存结构的组成大致有:

  • Buffer pool:缓冲池,用于存储数据页、索引页(包括自适应哈希索引、undolog缓冲区);
  • Change buffer:变更缓冲区(存在于buffer pool中);
  • Log buffer:日志缓冲区;

1.2 为什么要有内存结构?

如果所有数据操作,例如增删查改,统一都要与磁盘进行交互,那么innodb存储引擎处理数据的性能就会大大降低。因为磁盘IO速度会比内存IO速度要慢很多很多;

现代应用开发大多数原则Innodb的原因,就是因为Innodb可以通过内存、以及其他方式比如日志记录,确保不丢失事务一致性的情况下,提升性能;

1.3 Buffer pool 的结构

1.3.1 大致结构

Innodb中磁盘和内存的数据最小管理单位是
Buffer pool中组织和管理页(包括数据页、索引页)方式如图:

一个MySQL服务器中可以有多个instances(实例),每个实例都可以独立进行DML操作。
instances下管理多个Chunk,每个Chunk都被分配一块连续的物理内存。这块物理内存中就存放了被缓存的Page。

MySQL中支持通过innodb_buffer_pool_chunk_sizeinnodb_buffer_pool_instancesinnodb_buffer_pool_size来配置内存大小,但是不支持直接配置chunk的数量。我们可以通过(pool_size/instances)/chunk_size来计算每个chunk的大小

1.3.2 page的组织方式

在Innodb中,页与页的组织方式是通过控制块来实现的:

控制块其实就相当于节点,节点与节点之前相互连接,形成逻辑上的链表。每个instance下都会单独维护这种结构的链表(Free List 、Dirty List 、Clean List 后面会讲到)。
也就是说同一个instance下,chunk与chunk管理的page都组织在同一套逻辑链表下。

由于unlog 日志的组织方式也是页结构,所以把undo log放到了buffer pool中通过控制块进行管理;

1.3.3 page和chunk的初始化方式

每个chunk都有一块连续的内存。
控制块会从左到右进行初始化,而缓冲页则会从右到左进行初始化。如果中间不足以容纳一个(控制块+缓冲页),那么这块内存会变成碎片区无法被使用。

1.3.4 chunk的作用是什么?

每个chunk都会分配一块连续的物理内存。
MySQL中内存大小调整的最小单位是chunk。

  • 如果要进行扩容:像操作系统申请额外的chunk,并初始化,然后过载到Free List;
  • 如果要缩容:把空闲,没有被使用的chunk归还给操作系统;

1.3.5为什么要区分多个实例?

  • 之前讲到每一个instance可以独立的完成数据的DML操作,这里的主要作用就是降低单一缓冲池全局锁的争抢,提升MySQL的并发性能;
  • 每个instance都维护独立的Free List 、Dirty List 、Clean List,innodb把数据操作请求根据表空间id和页id分配给对应的instance完成DML操作;
  • 不同instance的数据相互不会干扰,因为Innodb保证buffer pool中每个缓冲页都是唯一的;

1.3.6 Buffer pool的缓存淘汰策略

1.3.6.1 缓存结构

Buffer pool中每个实例都会维护三个链表,以此来保证缓存淘汰:

  • Free List:保存已经从Flush List写回磁盘已经被用过的缓冲页;
  • Lru List:此链表实际参与buffer pool的缓存淘汰,记录了脏页和干净页,当有新的缓存页时,从Free List中获取;
  • FLush List:Lru List中所有脏页在这里都会有对应副本,当脏页写回磁盘后,会把空闲页重新叫给Free List;
1.3.6.2 缓存淘汰实现原理

Lru List参与缓存淘汰,Free List和Flush List用于辅助。
Lru List不是标准的Lru缓存结构,它的具体实现方式如图:

相比于传统Lru,MySQL中Lru缓存链表在中间开了个口。左侧约5/8是young区,右侧3/8是old区。当有新数据插入时,将新数据插入中间。

以用数据页被访问的缓存淘汰策略:
当访问的页在Lru list中,如果在yong区,直接移动到yong头。
如果在old区,实际上Innodb会记录每个old区中每个页在Old区停留的时间,默认1,000ms。大于这个值,移动到yong头,否则只移动到old头。

1.3.6. 3 为什么要把Lru缓存一分为二?

如果用传统Lru,当MySQL涉及临时的全表操作时,原先已经缓存过的热数据可能会被全部刷走。操作完成后,Lru链表中全是冷数据,需要重新热更新,这种场景下传统Lru就不适合使用了。

1.4 ChangeBuffer

1.4.1 changeBuffer作用

change buffer的主要作用是针对修改非唯一二级索引进行的。
这里先讲一个前置知识:

  • 磁盘操作中随机IO要比顺序写慢得多;
  • 实际上不论是二级索引还是聚集索引,随机的数据操作都会导致磁盘的随机IO,原因很简单,Innodb中是通过B+树来管理数据的,而树型结构的数据本身在物理层面就是随机分布的。所以索引操作不可避免会产生随机IO

而change buffer的作用就是尽可能的减少二级索引的随机IO次数,从而提升MySQL性能;

1.4.2 changeBuffer怎么减少二级索引随机IO的

Change Buffer 的核心思想是**“攒批异步,合并写入”**,其工作机制分为三步:

  1. 缓存修改(异步延迟):当对非唯一二级索引执行插入、更新或删除操作时,InnoDB 不会立即将受影响的索引页从磁盘读取到内存,而是将这次修改操作(如“在页号X插入主键ID=Y”)记录到 Change Buffer 中。这一步完全跳过了修改前的“随机读”IO
  2. 触发合并(读入即合):当后续某个查询需要读取该二级索引页,或者后台线程主动刷盘时,InnoDB 才将该索引页从磁盘加载到 Buffer Pool。
  3. 应用变更(批量落盘):将 Change Buffer 中针对该索引页积压的所有修改操作,**一次性合并(Merge)**到刚加载的内存数据页上,随后将该干净页异步刷回磁盘。

通过这种机制,Change Buffer 充分利用了计算机系统中的两个重要特性:

  • 时间局部性的应用(合并重复操作):如果某一行数据在短时间内被反复修改(例如同一行1秒内被Update了100次),没有Change Buffer时就要产生100次随机IO;有了它,这100次修改在内存中合并成1次最终结果,最终只触发1次磁盘写入,消除了时间维度上的重复IO
  • 空间局部性的应用(批量处理同页):如果修改操作分散在同一个索引页(物理上连续的16KB空间)内的不同行记录上,Change Buffer 会将这些散落的修改积攒起来。等到该页被加载时,所有修改被一次性批量应用并写入磁盘,将原本可能需要多次的随机IO,缩减为单次IO(写入一个完整的连续数据页)。

1.2.2 聚集索引/非唯一二级索引为什么不能用change buffer

聚集索引/非唯一二级索引都要求同一个表中,值必须唯一,唯一性校验不能是异步的。例如同时插入两个值,每个值的唯一索引都是1。那么后边合并数据的时候就乱套了。

1.5 AHI

1.5.1 概述

AHI,也就是自适应哈希,同样保存在Buffer pool中,但是只占buffer pool的很少容量。

  • AHI的key存储的二级制值,由对应行数据的主键和二级索引计算而来
  • AHI的valude存储的是对应所在的缓冲页的内存地址,以及偏移量,这样就可以快速对应行数据。

1.5.2 作用

AHI可以在不牺牲事务一致性的情况下,把高频查询数据以键值对的形式,存储在哈希表(内存)中,以提升查询性能。

1.5.3 为什么要引入AHI?

buffer pool中虽然有 page table的类似哈希表的结构,可以根据表空间id和页id,快速定位页,但是它不能快速查询具体的某个行数据。
也就是说AHI是针对某个频发查询数据行的操作进行优化。

1.6 page hash和AHI区别

page hash是每一个buffer pool中每一个instance都会维护的hash表数据,它能根据要查询的数据的表空间id+数据页id快速定位它所在的数据页。

特性Page Hash自适应哈希索引 (AHI)
核心目的快速定位数据页:判断一个磁盘数据页是否已在 Buffer Pool 中。快速定位数据行:加速对热点索引值的等值查询,跳过 B+ 树的遍历。
Key (键)(space_id, page_no)
即“表空间ID + 数据页号”。
索引键值 (或前缀)
由查询条件中的索引列值构成。
Value (值)缓存页的地址 / 控制块指针
指向 Buffer Pool 中对应的数据页。
数据行在 B+ 树叶子节点中的位置
或直接指向叶子节点中的记录。
所有者每个 Buffer Pool Instance 独立维护一份。全局维护,但内部可分区以减少竞争。

二、LogBuffer

2.1 作用

用于存储redo log。
redo log 重做日志,用于记录对应操作要修改的行、字段、值。
redo log的作用就是确保灾难恢复和事务的一致性。

2.2 工作流程

redolog会以事务为单位把更新操作保存到log buffer,然后根据不同策略写入磁盘,由innodb_flush_log_at_trx_commit控制:

  • =1实时写,每写入一个事务到内存,就刷盘一次(Innodb默认)
  • =0每秒写:每秒把已保存的修改操作刷盘;
  • =2根据操作系统调度:这种方式不确定性大;
    不论何种方式,刷盘的方式都是调用操作系统的write()接口,写入操作系统chache page,只是异步调用fsync()时机不同,实时写则是每个事务写入后,直接fsync()落盘。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/13 22:30:20

2026年GEO工具选型对比评测:五大维度如何避坑?

2026年,搜索行为早已不仅仅是关键词匹配。当用户开始习惯向AI提问“哪款工具适合某场景”或“某类产品有哪些推荐”时,企业必须意识到,品牌在AI回复中的可见性(GEO)已成为品牌资产管理的关键。然而,面对市面…

作者头像 李华
网站建设 2026/8/13 22:26:56

今年 30+,干了 8 年前端开发,转 Agent 开发整整两年了

今年 30,干了 8 年前端开发,转 Agent 开发整整两年了。 从最开始看着大模型文档一头雾水,到现在带团队帮企业落地线上 Agent 应用,我最大的感受就一句话:大部分想转 Agent 的程序员,从第一步就把重点给搞错…

作者头像 李华
网站建设 2026/8/13 22:21:38

如何通过专业可视化工具提升团队协作效率:3个实战技巧

如何通过专业可视化工具提升团队协作效率:3个实战技巧 【免费下载链接】diagram-design 29 editorial diagram types for Claude Code. Self-contained HTML SVG. No shadows, no Mermaid-slop. 项目地址: https://gitcode.com/GitHub_Trending/di/diagram-desig…

作者头像 李华
网站建设 2026/8/13 22:20:25

最新版本spring data jpa简介

围绕最新版 Spring 框架及 Spring Data,JPA 相关的演进主要集中在两个层面:基础依赖升级和开发体验优化。以下是核心新特性梳理。📦 基础升级:拥抱最新生态最新的 Spring 版本(以 Spring Framework 7.0 和 Spring Data…

作者头像 李华
网站建设 2026/8/13 22:19:48

Python工程师面试必考:30个基础题深度解析与实战应用

1. 项目概述:为什么Python面试题值得深挖?最近帮团队面试了几轮Python工程师,发现一个挺有意思的现象:很多候选人能把框架玩得很溜,但问到一些基础概念和底层原理时,回答就变得模棱两可,甚至直接…

作者头像 李华
网站建设 2026/8/13 22:18:24

Ubuntu无线网卡驱动安装与疑难排查全攻略

1. 项目概述:当Ubuntu遇上无线网卡 刚装好Ubuntu,满心欢喜准备联网探索开源世界,结果发现右上角的Wi-Fi图标是个灰色的小叉,或者干脆就不显示无线网络选项。这几乎是每一位从Windows或macOS转向Ubuntu的新手,以及为旧电…

作者头像 李华