InnoDB的磁盘结构是一个分层、组织精密的体系,核心围绕着​​表空间(Tablespaces)​​ 展开。它主要由以下几大部分组成:

​核心思想:数据存储在表空间文件中!​

  1. ​表空间(Tablespaces)​

    • ​定义:​​ InnoDB存储引擎用于管理存储的逻辑结构,本质上是一个或多个物理磁盘文件(.ibd)的集合。表空间是数据库数据和元数据的物理容器。
    • ​主要类型:​
      • ​系统表空间(System Tablespace):​

        • ​文件:​​ 通常是一个名为ibdata1(也可能有ibdata2等)的文件。
        • ​存储内容 (在未开启 innodb_file_per_table 或特定元数据)​
          • ​数据字典(Data Dictionary):​​ 包含关于表结构、列、索引、外键等数据库对象的元数据。
          • ​Change Buffer:​​ 用于加速对非唯一二级索引的插入、删除和更新操作(当目标页不在缓冲池中时)。
          • ​Doublewrite Buffer:​​ ​​关键机制​​,用于防止页部分写入(Partial Page Write)。在将页(Page)写入数据文件之前,会先将它们写入这个缓冲区。如果发生崩溃,可以利用这个缓冲区来恢复完整的页。
          • ​Undo Log:​​ (在 MySQL 5.6 之前以及 5.7.1 之后可以配置,默认在系统表空间)​**​ 记录数据修改前的值,用于事务回滚(ROLLBACK)和多版本并发控制(MVCC)。
          • ​表数据(Table Data):​​ ​​在 MySQL 5.6.6 之前,或即使开启了 innodb_file_per_table 但未完全迁移完的表,数据会存储在系统表空间。​​ MySQL 5.6.6 引入innodb_file_per_table后,默认新创建的用户表的数据会存储在独立的表空间文件。
      • ​独立表空间/每表文件表空间(File-Per-Table Tablespaces):​
        • ​文件:​​ 每个用户表对应一个独立的.ibd文件(存储在数据库目录下,如your_database/your_table.ibd)。
        • ​启用方式:​​ 设置innodb_file_per_table=ON(MySQL 5.6.6 及以后版本默认开启)。
        • ​存储内容:​
          • ​该表的数据(Data):​​ 即表中的行记录。
          • ​该表的索引(Indexes):​​ 包括聚簇索引(主键索引)和所有二级索引。
          • ​该表的Undo Log:​​ 该表关联的Undo日志段(自 MySQL 8.0 起)。
        • ​优点:​
          • ​更好的空间管理:​​ 可以单独压缩、备份、恢复、删除单个表空间文件。删除表时可以直接删除.ibd文件回收空间(系统表空间不行)。
          • ​性能提升:​​ 可以减少碎片,优化 I/O。
          • ​便于迁移。​
      • ​通用表空间(General Tablespaces):​
        • ​文件:​​ 用户自定义的.ibd文件(不在数据库目录下)。
        • ​创建方式:​CREATE TABLESPACE ... ADD DATAFILE ...
        • ​存储内容:​​ 用户可以指定将多个表存储在其中。
        • ​用途:​​ 灵活管理存储,可以集中存放多个表,便于管理。支持压缩。
      • ​Undo 表空间(Undo Tablespaces):​
        • ​文件:​​ 通常命名为undo_001, undo_002等(在MySQL数据目录或配置的innodb_undo_directory下)。
        • ​存储内容:​​ ​​专门存放Undo日志记录。​
        • ​启用:​​ MySQL 5.6 开始引入配置,MySQL 5.7 开始推荐分离,MySQL 8.0 默认至少创建2个初始的Undo表空间并管理其生命周期。
        • ​目的:​​ 将Undo日志从系统表空间中分离出来,提升管理灵活性和性能。支持在线回收Undo空间(truncate)。
      • ​临时表空间(Temporary Tablespaces):​
        • ​文件:​​ 默认有ibtmp1
        • ​存储内容:​​ 存放临时表(用户创建的CREATE TEMPORARY TABLE)和查询执行过程中内部临时表(internal temporary tables)的磁盘数据部分。
        • ​特点:​​ 重启后会重建(数据丢失)。可以配置大小上限(innodb_temp_data_file_path)。
  2. ​表空间的内部结构:段、簇、页​

    每个表空间内部进一步被组织成更小的逻辑单元:

    • ​段(Segment):​

      • 表空间的主要组织结构单元。
      • 每个索引在表空间中占据两个主要的段:
        • ​叶子节点段(Leaf Segment / B-tree Leaf Node Segment):​​ 存储索引的​​叶子节点​​(对于聚簇索引,叶子节点存储的是完整的行数据;对于二级索引,存储的是索引列和主键值)。
        • ​非叶子节点段(Non-Leaf Segment / B-tree Non-Leaf Node Segment):​​ 存储索引的​​非叶子节点​​(即内部节点,用于导航定位到叶子节点)。
      • 此外,还存在用于管理回滚段(Undo Segment)的段。回滚段本身包含多个Undo Slot。
      • 段由​​簇(Cluster)​​ 组成。
    • ​簇(Extent / Cluster):​
      • ​组成:​​ 由​​连续​​的​​页(Page)​​ 组成。
      • ​大小:​​ ​​固定为 1MB​​(在页大小为默认16KB的情况下,一个簇包含 1MB / 16KB = 64 个连续的页)。
      • ​目的:​​ 分配存储空间的基本单位(最初分配给段时,分配一个簇),减少碎片,提高I/O效率(连续存储)。
    • ​页(Page):​
      • ​定义:​​ ​​InnoDB磁盘管理的最小单位。​​ 所有数据的读写操作,都是以页为单位进行的。数据在写入磁盘之前必须先读入内存中的缓冲池(Buffer Pool)进行操作。
      • ​大小:​​ ​​固定 16KB​​(可以通过编译时参数修改,但非常不推荐,兼容性问题多)。
      • ​类型:​​ 根据存储内容的不同,页有多种类型:
        • ​数据页(Index Page / Data Page):​​ ​​最常见的页类型,用于存储B+树索引的节点(叶子节点和非叶子节点),即实际的行数据和索引项。​
        • ​Undo页(Undo Page):​​ 存储Undo日志记录。
        • ​系统页(System Page):​​ 存储数据字典信息等(主要存在于系统表空间)。
        • ​Insert Buffer Bitmap Page:​​ 管理Change Buffer空间使用情况。
        • ​Insert Buffer Free List Page:​​ 管理Change Buffer的空闲列表。
        • ​FSP_HDR (File Space Header Page):​​ 表空间的第一个页,存储表空间整体元信息,如空间ID、页总数、簇使用情况等。
        • ​INODE Page:​​ 存储段(Segment)的信息(FSP_HDR页包含INODE页的指针)。
        • ​XDES Page (Extent Descriptor Page):​​ 跟踪簇的使用情况(FSP_HDR页包含第一个XDES页的指针)。
        • ​等等...​
      • ​数据页(Index/Data Page)结构剖析:​​ 这是理解InnoDB行存储的核心。
        • File Header (38B):记录页的通用信息,如页类型(INDEX)、前一页/后一页指针(构成双链表)、页的校验和(Checksum)、页在表空间中的位置(SPACE_ID & PAGE_NO)等。
        • Page Header (56B):记录页的状态信息,如存储记录数、槽(Slot)数、堆(Heap)信息、垃圾记录链表头指针、上次插入位置、页面层级(在B+树中的深度)等。
        • Infimum + Supremum Records (13B each):系统定义的虚拟最小记录(Infimum)和最大记录(Supremum)。用户记录都逻辑上位于两者之间,便于边界处理。
        • User Records (行记录, Row Records):​​ 实际存储行数据的区域。记录按​​主键顺序​​紧密存储(对于聚簇索引叶子页)。记录有特定的格式。
        • Free Space:​​ 页中尚未使用的空间。删除记录或插入较小记录后,新记录可能会优先使用这里。
        • Page Directory (Slot Array):存储页内记录的相对位置(逻辑偏移量),结构是一个稀疏索引。每个槽(Slot)指向页内的一个记录(通常是按主键顺序每组最后几条记录中的一个)。用于页内快速二分查找定位记录。
        • File Trailer (8B):校验点,包含页的校验和。页刷盘后,将此校验和与File Header中的校验和比对,确保页写入完整。
  3. ​行格式(Row Format)​

    • 决定了​​用户记录(User Records)​​ 在数据页内是如何物理存储的。
    • ​常见格式 (由ROW_FORMAT决定):​
      • REDUNDANT (过时):​​ MySQL 5.0.3 之前的默认格式。格式最紧凑但效率相对较低。
      • COMPACT (流行):​​ 比REDUNDANT更高效的存储格式。减少约20%的行空间,特别是对于可变长类型和NULL值。它将变长字段的长度信息集中放在行记录的开头。
      • DYNAMIC (默认):​​ ​​MySQL 5.7.9 (InnoDB 1.2) 及以后版本的默认格式。​​ 是COMPACT格式的增强。主要改进在于处理大对象(BLOB, TEXT, JSON, 大的VARCHAR)。在这些列很大的情况下,DYNAMIC格式只在页中存储一个20字节的指针指向单独分配的"溢出页(Overflow Page)"存储实际的大值。而COMPACT会尝试在行内存储768字节的前缀。这使得DYNAMIC对于包含大对象的表更高效,​​显著减少了行溢出和碎片​​。
      • COMPRESSED:​​ 类似于DYNAMIC,但增加了表/页级别的数据压缩功能(使用zlib)。适用于读密集、存储敏感的场景,牺牲一定CPU开销换取空间节省。
    • ​核心优化点:​
      • DYNAMIC格式通过使用溢出页指针,极大地提升了大字段操作的效率和存储空间利用率,是现代应用推荐使用的格式。
  4. ​索引组织存储​

    • ​聚簇索引(Primary Key / Clustered Index):​

      • InnoDB表的数据存储方式基于聚簇索引组织。
      • ​每张表必须且只能有一个聚簇索引(主键索引)。​
      • 表的数据(行记录)​​物理上​​就是按照主键值的顺序存储在​​叶子节点​​上的。
      • 非叶子节点存储主键值以及指向子节点的指针(页号+槽号)。
      • ​优点:​​ 按主键检索非常高效(1-3次磁盘I/O通常可定位)。范围查询效率高(连续存储)。
      • ​缺点:​​ 主键值大小影响所有二级索引的大小和性能(因为二级索引叶子节点存储主键值)。主键修改成本高(需要移动行)。
    • ​二级索引(Secondary Index / Non-Clustered Index):​
      • 叶子节点​​不存储完整的行数据​​。
      • ​叶子节点存储的是:​
        • ​索引的列值 (The key columns of the secondary index)​
        • ​对应行的主键值 (The primary key columns of the clustered index)​
      • ​定位完整数据:​​ 如果查询所需列不在二级索引覆盖的列中(即非覆盖索引查询),则需要通过二级索引叶子节点记录的主键值,回到聚簇索引(主键索引)中进行一次“回表”查找(通常通过B+树查找)来获取完整的行数据。​​这是影响二级索引效率的关键因素!​索引覆盖(Covering Index)可以避免回表。
    • ​没有显式定义主键怎么办?​
      • InnoDB会自动检查所有唯一非空索引,​​选择一个唯一的非空索引(第一个找到的)作为聚簇索引​​。
      • 如果找不到这样的索引,InnoDB会​​隐式创建一个名为GEN_CLUST_INDEX的自增ROWID(6字节)作为隐藏的主键(聚簇索引)​​。隐藏主键会记录在数据字典中,但对用户不可见,也会增加二级索引大小(叶子节点需要存储这个大的ROWID)。
  5. ​其他重要磁盘组件​

    • ​重做日志文件(Redo Log Files):​

      • ​文件:​​ 通常命名为ib_logfile0ib_logfile1(默认两个,大小可配)。
      • ​存储内容:​​ 顺序写入的日志记录,记录了​​物理层面上​​对数据页的修改操作(逻辑物理混合)。它是​​事务持久性的核心保证​​。
      • ​工作原理 (Write-Ahead Logging - WAL):​
        1. 事务提交前,​​必须先​​将对数据页的所有修改记录写入(持久化到磁盘)Redo Log文件。
        2. 数据页的修改可能还停留在Buffer Pool中,没有写回磁盘数据文件(.ibd)。
        3. 如果发生崩溃,重启时通过重放(Replay)这些Redo Log记录,可以将​​已经提交的事务​​所做的修改重新应用到数据文件,保证​​持久性(Durability)​​。
      • ​循环写入:​​ Redo Log文件是循环使用的。当写满最后一个文件时,会覆盖写第一个文件(前提是第一个文件中的修改对应的脏页已经被刷盘)。
      • ​与磁盘结构的关联:​​ Redo Log记录了所有对数据页(最终存储在表空间文件中)的更改。
    • ​Doublewrite Buffer (物理实现):​
      • 虽然逻辑上属于系统表空间的一部分,但它是一个特殊的磁盘区域。
      • 在将脏页写回其真正的表空间数据文件位置​​之前​​,InnoDB会先将脏页的一个副本写入Doublewrite Buffer(位于系统表空间中连续的固定位置)。写Doublewrite Buffer是顺序写。
      • 之后才会真正将脏页写入其在表空间数据文件(.ibd)中的最终位置(随机写)。
      • ​目的:​​ 解决部分页写入问题。如果页在写入最终位置的过程中发生崩溃导致页损坏(只写了16KB的一部分),InnoDB在恢复时,可以从Doublewrite Buffer中找到该页的一个完好副本,并用它来覆盖损坏的页。由于Doublewrite Buffer的写是原子性且顺序的,它能保证副本页的完整性。然后可以安全地使用Redo Log重做该页的变化。​​为页写入失败提供了一道安全网。​

​图解层次关系 (从大到小):​

   +---------------------------+
| Database | # 数据库实例,包含多个表空间
+---------------------------+
|
v
+---------------------------+
| Tablespace(s) | # 逻辑容器: ibdata1, table.ibd, undo_001, ibtmp1
+---------------------------+
|
+--------------------------------------------------------+
| |
v v
+-----------------------+ +--------------------------+ +----------------------+
| Segment (e.g., Index | | Segment (e.g., Undo Seg) | | ... Other Segments ...|
| Leaf Segment) | | | | |
+-----------------------+ +--------------------------+ +----------------------+
| |
v v
+----------------------+ +----------------------+
| Extent |----->| Extent | # 由连续的64个页组成 (1MB for 16K Page)
+----------------------+ +----------------------+
|
v
+----------------------+ +----------------------+
| Page (1) |----->| Page (2) | # 16KB 最小单位
+------------+---------+ +------------+---------+
| |
v (Inside Page Structure) v (Inside Page Structure)
+---------------------------------------------------+
| File Header | Page Header | Infimum | User Records |
| (38B) | (56B) | (13B) | (Rows!) |
| ... Free Space ... | Page Directory | File Trailer|
| | (Slots) | (8B) | |
+---------------------------------------------------+
|
v (Inside User Records)
+---------------------------------------------------+
| Row Format (e.g., Dynamic): |
| - Field Length Offsets |
| - Trx ID & Roll Pointer (for MVCC) |
| - Non-NULL Fixed-Length Columns |
| - Non-NULL Variable-Length Columns |
| - NULLable Columns Bitmap |
| - Overflow Page Pointers for large columns |
+---------------------------------------------------+

​总结关键点:​

  1. ​表空间为中心:​​ 所有数据最终存储在表空间文件(.ibd, ibdata1, undo_001, ibtmp1)。

  2. ​页是最小单位:​​ 所有的磁盘I/O(读写、刷盘、缓存)都以16KB的页为单位进行。

  3. ​索引组织数据:​​ 表数据按主键顺序(聚簇索引)物理存储。二级索引存储索引列+主键值。

  4. ​页内结构:​​ 数据页有严谨的结构(页头、记录头、行记录、槽目录、页尾),DYNAMIC行格式优化了大字段存储。

  5. ​段、簇管理:​​ 段(叶子段、非叶子段)是表空间的主要单元,由连续的簇(64个页,1MB)组成,簇再由连续的页组成,利于减少碎片和提高效率。

  6. ​核心机制:​

    • ​重做日志(Redo Log):​​ 保证事务持久性(先写日志)。
    • ​Doublewrite Buffer:​​ 保证页写入的原子性,防止页部分写入损坏。
    • ​Change Buffer:​​ 加速二级索引的DML操作(在非唯一索引上)。
    • ​Undo Log (在Undo表空间):​​ 支持事务回滚和MVCC。
  7. ​分离是现代趋势:​

    • 使用innodb_file_per_table=ON将用户表数据分离到独立的.ibd文件。
    • 使用Undo表空间单独管理Undo日志。
    • 临时表空间管理临时数据。

理解这些磁盘结构,有助于你更深入地理解InnoDB的运作原理,从而在优化查询(例如设计高效的索引避免回表)、配置存储参数、分析性能瓶颈和进行故障排查时做出更明智的决策。

InnoDB 磁盘结构的更多相关文章

  1. MySQL之 InnoDB记录结构(转自掘金小册 MySQL是怎样运行的,版权归作者所有!)

    以下内容来自掘金小册 MySQL 是怎样运行的:从根儿上理解 MySQL 版权归原作者所有! 页是MySQL中磁盘和内存交互的基本单位,也是MySQL是管理存储空间的基本单位. 指定和修改行格式的语法 ...

  2. 第五节:从一条记录说起——InnoDB记录结构

    <MySQL 是怎样运行的:从根儿上理解 MySQL>第五节:从一条记录说起——InnoDB记录结构 准备工作 现在只知道客户端发送请求并等待服务器返回结果.    MySQL什么方式来访 ...

  3. 详细了解 InnoDB 内存结构及其原理

    最近发现,文章太长的话,包含的信息量较大, 并且需要更多的时间去阅读.而大家看文章,应该都是利用的一些碎片时间.所以我得出一个结论,文章太长不太利于大家的吸收和消化.所以我之后会减少文章的长度,2-3 ...

  4. MySQL之 InnoDB 内存结构

    从MySQL 5.5版本开始默认 使用InnoDB作为引擎,它擅长处理事务,具有自动崩溃恢复的特性,在日常开发中使用非常广泛 下面是官方的InnoDB引擎架构图,主要分为内存结构和磁盘结构两大部分. ...

  5. MySQL-InnoDB磁盘结构

    主要阐述InnoDB存储引擎(MySQL5以后的默认引擎). 数据库中最基本的组成结构是数据表,视觉上的表和其对应的磁盘结构如下: 此图参考了厦门大学课堂:MySQL原理 .但是视频中一些更多细节没有 ...

  6. UBIFS 文件系统分析1 - 磁盘结构【转】

    转自:http://blog.csdn.net/kickxxx/article/details/7109662 版权声明:本文为博主原创文章,未经博主允许不得转载. ubifs磁盘结构 UBIFS文件 ...

  7. [转+整理]LINUX学习笔记(1):磁盘结构及分区

    整理自: http://vbird.dic.ksu.edu.tw/linux_basic/0130designlinux_2.php http://lengjianxxxx.blog.163.com/ ...

  8. linux 磁盘管理三部曲——(1)磁盘结构,认识分区

    最近小编整理了磁盘管理的相关知识,发现还是挺多的,所有就分了三个部分来给大家分享一下: 1.磁盘结构,认识分区 2.管理分区,文件系统格式化 3.mount挂载,/etc/fstab配置文件 这篇就先 ...

  9. [svc][op]磁盘(结构)容量计算

    磁盘结构和容量计算 fdisk -l显示信息详解 [root@www.linuxidc.com ~]# fdisk -l Disk /dev/sda: bytes heads, sectors/tra ...

  10. 使用innodb_ruby探查Innodb索引结构

    使用innodb_ruby探查Innodb索引结构 innodb_ruby 是使用 Ruby 编写的 InnoDB 文件格式解析器.innodb_ruby 的目的是暴露一些其他隐藏的 InnoDB 原 ...

随机推荐

  1. 电梯题目集总结性Blog

    一.前言 对这三次题目集的总结:   这三次作业的难度是层层递进的.题目数量安排得当,给的时间也足够用.前面的基础题像搭积木一样,带着我们一步步熟悉怎么设计类和对象:但每次的最后一题就像突然升级的关卡 ...

  2. WPF 基于Transform实现画布超出边界触发计算

    有些场景需要对画布边界做界限控制,此时需要计算画布的四个方向的界限和极值 先看效果图: 画布在通过RenderTransform 做变换,由于在变换的过程中,实际的宽高没有改变,需要通过Transfo ...

  3. React-Native开发鸿蒙NEXT-图片上传

    .markdown-body { line-height: 1.75; font-weight: 400; font-size: 16px; overflow-x: hidden; color: rg ...

  4. css样式修改-悬浮数字

    代码实现 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF- ...

  5. Linux ls 查看目录结构与文档信息

    摘要:Linux ls命令用于列出目标目录中所有的子目录和文件,发掘并掌握ls命令及其参数设置可以驾轻就熟地管理文件,随心所欲地浏览并确定所在的位置! ls命令介绍   今天,楼兰胡杨继续跟各位猿友一 ...

  6. 浅谈Spring、Spring MVC、Spring Boot和Spring Cloud的关系和区别

      Spring 框架就像一个家族,有众多衍生产品,例如 boot.security.jpa等等.但它们的基础都是Spring的IOC和AOP等.IOC提供了依赖注入的容器,AOP解决了面向横切面编程 ...

  7. MyBatis常见面试题:通常一个Xml映射文件,都会写一个Dao接口与之对应,请问,这个Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗?

      MyBatis常见面试题:通常一个Xml映射文件,都会写一个Dao接口与之对应,请问,这个Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗?   Dao接口即Mapper接 ...

  8. 2022 电赛C题 巡线基础模块代码(带控制)

    巡线功能模块 from maix import camera, display, gpio, pwm class FindLine(): def __init__(self): self.THRESH ...

  9. 推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)

    推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化 ...

  10. Java常用类Object

    1 package com.lv.study.pm; 2 3 public class TestObject { 4 5 public static void main(String[] args) ...