面试官问我 InnoDB 的物理存储结构!

前段时间去面试,面试官突然问我:聊聊 InnoDB 的物理存储结构吧!

树义突然又眼圈一黑,啥都想不起来了!

虽说之前有大致了解过 MySQL,但对 InnoDB 的物理结构,却真的没咋了解过!那么,今天就来聊聊 InnoDB 的物理存储结构吧!

相信很多人都知道逻辑结构和物理结构这两个概念,但是都很好奇它们的区别是什么?

简单地说:所谓物理存储结构,指的是 MySQL 的数据是怎么存储在物理介质上的,由哪些磁盘文件组成。所谓逻辑存储结构,指的是这些数据是如何有结构地组织起来的。

此文所描述的 InnoDB 物理存储结构,依据的是 MySQL 8.0 版本。

从 MySQL 官方文档中,我们可知 InnoDB 在物理层面上可划分为如下 7 个模块:

  • 系统表空间(System Tablespace)
  • 双写缓存文件(Doublewrite Buffer Files)
  • Undo 表空间(Undo Tablespaces)
  • Redo Log 文件(Redo Log)
  • 独占表空间(File-Per-Table Tablespaces)
  • 通用表空间(General Tablespaces)
  • 临时表空间(Temporary Tablespaces)

而在这 7 个模块中,最为关键的是如下三个模块:系统表空间(System Tablespace)、独立表空间(File-Per-Table Tablespaces)、日志文件组(Redo Log)。

InnoDB 磁盘存储结构 MySQL 8.0

系统表空间(System Tablespace)

在开始之前,我们需要理解表空间这个概念。其实表空间,就是存储表的空间之意。它是 InnoDB 用于描述数据存储的术语,大致是存储表相关数据的地方之意。系统表空间,顾名思义就是 InnoDB 这个系统的默认表空间,也叫共享表空间,对应的是 MySQL 数据目录下的 ibdata1 文件。如果我们将 innodb_file_per_table 设置为 off,那么我们使用 CREATE TABLE 语句创建的表数据,都会存储在系统表空间中。

而如果我们将 innodb_file_per_table 设置为 on,则每个表将独立地产生一个表空间文件,以 ibd 结尾,数据、索引、表的内部数据字典信息都将保存在这个单独的表空间文件中。但是还有一些信息,例如 undo log 信息,还是会保存在系统表空间中。例如我们在 test 数据库中创建了一个名为 user 的表,那么就会在 MySQL 的数据文件夹的 test 文件夹下,有一个名为 user.ibd 文件。

我们注意到系统表空间还有一个名为 change buffer 的东西,它到底是啥东西呢?

change buffer,其实在之前版本是插入缓冲(insert buffer),后续版本变成了 change buffer(参考:内幕 2.4.1 章节)。这一块区域就是 Change Buffer。5.5 之前叫 Insert Buffer 插入缓冲,现在也能支持 delete 和 update,最后把 Change Buffer 记录到数据页的操作叫做 merge。

这里面有一句话很关键:除了主键聚合索引外,还产生了一个 name 列的辅助索引,对于该非聚集索引来说,叶子节点的插入不再有序,这时就需要离散访问非聚集索引页,插入性能变低。

这句话的意思是:聚集索引的插入是有序自增的,那么插入的时候直接跟在后面就可以了,不需要再做其他随机访问操作。而由于插入的非聚集索引列,并不是有序的,可能会插在中间,这时候就需要看看中间这个页是否加载到内存里。如果加载了,那还好,那就做 B+ 树操作,调整就行。不在内存里的话,那就麻烦了,需要读取多次 page 到内存。

为了提高效率,就弄了一个 insert buffer,简单地说,就是把多次 insert 或者修改操作,先缓存起来,然后等到差不多的时候,再一起去做,提高效率,避免多次 IO 读取。

插入缓冲,并不是缓存的一部分,而是物理页,对于非聚集索引的插入或更新操作,不是每一次直接插入索引页。而是先判断插入的非聚集索引页是否在缓冲池中。如果在,则直接插入,如果不再,则先放入一个插入缓冲区中。然后再以一定的频率执行插入缓冲和非聚集索引页子节点的合并操作。

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

双写缓存文件(Doublewrite Buffer Files)

如果说插入缓冲带给 InnoDB 存储引擎的是性能,那么双写带给 InnoDB 存储引擎的是数据的可靠性。当数据库宕机时,可能数据库正在写一个页面,而这个页只写了一部分(比如 16K 的页,只写了前 4K 的页),我们称之为写失效。在 InnoDB 存储引擎未使用 double write 之前,曾出现过因为部分写失效而导致数据丢失的情况。

InnoDB 存储引擎 double write 的体系架构如下图所示:

双写缓存(double write)示意图

double write 由两部分组成:一部分是内存中的 double write buffer,大小为 2MB。另一部分是物理磁盘上共享表空间中连续的 128 个页,即两个区,大小同样为 2MB。

当缓冲池的脏页刷新时,并不直接写磁盘,而是会他通过 memcpy 函数将脏页先拷贝到内存中的 doublewrite buffer,之后通过 doublewrite buffer 再分两次,每次写入 1MB 到共享表空间的物理磁盘上,然后马上调用 fsync 函数,同步磁盘,避免缓冲写带来的问题。在这个过程中,因为 doublewrite 页是连续的,因此这个过程是顺序写,开销不是很大。

在完成 doublewrite 页的写入之后,再将 doublewrite buffer 中的页写入各个表空间文件中,此时的写入则是离散的。我们可以通过 show global status like ‘innodb_dblwr%’\G 观察具体情况。

所以说双写,其实指的是刷脏页的时候,即会将脏页数据写入共享表空间的 2 个页中,也会写入具体的表空间中,共享表空间的数据起到备份作用。

如果操作系统在将页写入具体的表空间过程中崩溃了,在恢复过程中,InnoDB 存储引擎可以从共享表空间中的 doublewrite 中找到该页的一个副本,将其拷贝到表空间文件,再应用重做日志。

Undo 表空间(Undo Tablespaces)

undo Log 的数据默认在系统表空间 ibdata1 文件中,因为共享表空间不会自动收缩,也可以单独创建一个 undo 表空间。

一些疑问,关于 rollback segment 与 undo log?

很多时候,我们不太懂,为啥一些说 undo log 在系统表空间,而官方的图却有 undo tablespace ?下面这段话,描述得很清楚,原因是版本变化!

Rollback Segment(rseg)称为回滚段。Mysql5.6 之前 undo 默认记录到系统表空间(ibdata),如果开启了 innodb_file_per_table ,将放在每个表的.ibd 文件中。5.6 之后还可以创建独立的 undo 表空间,8 之后更是默认打开独立 undo 表空间,最低数量为 2,这样才能保证至少一个 undo 表空间进行 truncate,一个 undo 表空间继续使用。

每个 rollback Segment 中默认有 1024 个 undo log segment,mysql5.5 后 1 个 undo 表空间支持 128 个 rollback Segment。0 号 rollback Segment 默认在系统表空间 ibdata 中,1-32rollback Segment 在临时表空间,33~128 在独立 undo 表空间中(没有打开则在系统表空间 ibdata 中,这样系统表空间会太大),所以 1 个表空间最多支持 96*1024 个事务,超了就报错啦。

一个 undo log segment 称为 undo log 或 undo slot 或 undo;一个 undo log 对象对应多个 undo log record,也就是记录的历史版本。(Rollback segment -> 多个 Undo log segment (undo log) -> 多个 undo log record)。

疑问 2:mysql rollback segment 和 undo segment 区别

感觉这两个应该是差不多的呀?

结论:Rollback segment 与 undo segment 是包含的关系,每个 Rollback segment 有 1024 个 undo segment。

undo log 有两个作用:提供回滚和多个行版本控制 (MVCC)。

在数据修改的时候,不仅记录了 redo,还记录了相对应的 undo,如果因为某些原因导致事务失败或回滚了,可以借助该 undo 进行回滚。

undo log 和 redo log 记录物理日志不一样,它是逻辑日志。可以认为当 delete 一条记录时,undo log 中会记录一条对应的 insert 记录,反之亦然,当 update 一条记录时,它记录一条对应相反的 update 记录。

rollback segment 称为回滚段,每个回滚段中有 1024 个 undo log segment。

Redo Log 文件(Redo Log)

redo log 即重做日志,从字面意思来看,其表示可以将事情重做一遍的意思。而事实上,它确实是代表着这个意思。对于上文的更新语句 update t set c=c+1 where id = 2,我们的正常实现思路应该是:

找到 id 为 2 的记录,取出其 c 字段的值。

将 c 字段的值加一,之后将 id 为 2 的字段的 c 字段更新。

但实际上 MySQL 并不是这么做的,因为上述这种实现方式虽然能实现,但是每次都要去读取磁盘查找记录、写入磁盘更新记录,整个过程的磁盘 IO 成本很高。为了提高效率,MySQL 使用了一种叫做 WAL(Write-Ahead Logging)的技术,即写之前先记录变更日志(redo log),等待合适的时间再将其变更应用到数据库里。因为我们将操作记录下来了,所以我们可以复现这个操作,这就好像我们将事情重现了一样,因此叫 redo log。

使用 WAL 技术,上面这条更新语句的大致实现思路就变成了:

记录下更新操作日志:其要将 id 为 2 的记录的 c 字段加 1。

某个时刻,MySQL 数据库应用这个 redo log 日志,将数据库 id 为 2 的记录的 c 字段加 1。

注意:redo log 并不会应用于磁盘的表空间,而是在重启时应用于内存表空间缓存,用于实现 crash-safe。

可以看到,使用 WAL 技术的方式,可以不需要去读写磁盘,极大提高了执行效率。

我们举一个很形象的例子来理解 WAL 技术。想象有一个酒馆,生意非常好,老板也愿意赊账。每次别人想要赊账,老板都得去翻账本,看看这个人有没有赊过账,有赊账的话就需要在原来的赊账金额上再加上本次消费的金额。

在平时酒馆人不多的时候,这种方式还是可以应付应付的。但是一旦到了酒馆高峰期的时候,每个人都等着结账,这时候再用这种方式去结账,很可能让客户等太久,引起民愤。于是老板想了个办法:我不去账本上找谁赊账了,我直接在黑板上记录下谁赊账了多少钱。例如:张三赊账 3 块银元,李四赊账 4 块银元。

等生意没那么忙的时候,老板拿出账本,将粉板上的变更记录进账本:哦,之前张三赊账了 4 块银元,现在又赊账了 3 块银元,所以张三现在总共赊账 7 块银元。在这个例子中,账本就相当于我们的 MySQL 数据库,粉板就相当于我们的 redo log,它将消费记录保存下来。

独占表空间(File-Per-Table Tablespaces)

如果我们将 innodb_file_per_table 设置为 on,则每个表将独立地产生一个表空间文件,以 ibd 结尾,数据、索引、表的内部数据字典信息都将保存在这个单独的表空间文件中。但是还有一些信息,例如 undo log 信息,还是会保存在系统表空间中。例如我们在 test 数据库中创建了一个名为 user 的表,那么就会在 MySQL 的数据文件夹的 test 文件夹下,有一个名为 user.ibd 文件。

通用表空间(General Tablespaces)

通用表空间是后续的 MySQL 推出的表空间,其与系统表空间类似,可以用于存储表的数据和索引。其作用是可以将一些业务逻辑不同的表,存放在这个通用表空间中,从而达到物理隔离的作用。

临时表空间(Temporary Tablespaces)

存储临时表的数据,包括用户创建的临时表,和磁盘的内部临时表。对应数据目录下的 ibtmp1 文件。当数据服务器正常关闭时,该表空间被删除,下次重新产生。

参考资料:

  • MySQL :: MySQL 5.7 Reference Manual :: 14.6.3 Tablespaces
  • InnoDB 内存结构和磁盘结构_wang2963973852 的博客 – CSDN 博客
  • [Mysql] 漫游 undo log | 土川的自留地
  • 详细分析 MySQL 事务日志 (undo log) – 裸奔的小鸵鸟 – 博客园

文章来源网络,作者:运维,如若转载,请注明出处:https://shuyeidc.com/wp/231962.html<

(0)
运维的头像运维
上一篇2025-04-19 22:56
下一篇 2025-04-19 22:58

相关推荐

  • 个人主题怎么制作?

    制作个人主题是一个将个人风格、兴趣或专业领域转化为视觉化或结构化内容的过程,无论是用于个人博客、作品集、社交媒体账号还是品牌形象,核心都是围绕“个人特色”展开,以下从定位、内容规划、视觉设计、技术实现四个维度,详细拆解制作个人主题的完整流程,明确主题定位:找到个人特色的核心主题定位是所有工作的起点,需要先回答……

    2025-11-20
    0
  • 社群营销管理关键是什么?

    社群营销的核心在于通过建立有温度、有价值、有归属感的社群,实现用户留存、转化和品牌传播,其管理需贯穿“目标定位-内容运营-用户互动-数据驱动-风险控制”全流程,以下从五个维度展开详细说明:明确社群定位与目标社群管理的首要任务是精准定位,需明确社群的核心价值(如行业交流、产品使用指导、兴趣分享等)、目标用户画像……

    2025-11-20
    0
  • 香港公司网站备案需要什么材料?

    香港公司进行网站备案是一个涉及多部门协调、流程相对严谨的过程,尤其需兼顾中国内地与香港两地的监管要求,由于香港公司注册地与中国内地不同,其网站若主要服务内地用户或使用内地服务器,需根据服务器位置、网站内容性质等,选择对应的备案路径(如工信部ICP备案或公安备案),以下从备案主体资格、流程步骤、材料准备、注意事项……

    2025-11-20
    0
  • 如何企业上云推广

    企业上云已成为数字化转型的核心战略,但推广过程中需结合行业特性、企业痛点与市场需求,构建系统性、多维度的推广体系,以下从市场定位、策略设计、执行落地及效果优化四个维度,详细拆解企业上云推广的实践路径,精准定位:明确目标企业与核心价值企业上云并非“一刀切”的方案,需先锁定目标客户群体,提炼差异化价值主张,客户分层……

    2025-11-20
    0
  • PS设计搜索框的实用技巧有哪些?

    在PS中设计一个美观且功能性的搜索框需要结合创意构思、视觉设计和用户体验考量,以下从设计思路、制作步骤、细节优化及交互预览等方面详细说明,帮助打造符合需求的搜索框,设计前的规划明确使用场景:根据网站或APP的整体风格确定搜索框的调性,例如极简风适合细线条和纯色,科技感适合渐变和发光效果,电商类则可能需要突出搜索……

    2025-11-20
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注