MySQL InnoDB 表数据结构存储方式详解
InnoDB 是 MySQL 默认的存储引擎,采用 行存储,支持 事务、行级锁、外键,并通过 B+ 树索引 高效管理数据。本笔记详细介绍 InnoDB 表的数据存储结构、索引组织表(Clustered Index)、二级索引、页结构、行格式 及相关机制。
一、InnoDB 表的整体存储结构
InnoDB 的存储结构分为以下几个层次:
表空间(Tablespace)
├── 段(Segment)
│ ├── 区(Extent)
│ ├── 页(Page)
│ └── 行(Row)
- 表空间(Tablespace)
存放表数据和索引的逻辑容器,可以是系统表空间(ibdata)或独立表空间(.ibd 文件)。 - 段(Segment)
表空间中的逻辑分配单位,分为 数据段(Data Segment) 和 索引段(Index Segment)。 - 区(Extent)
每个区大小固定为 1MB,包含 64 个页(每页 16KB)。 - 页(Page)
InnoDB 的最小磁盘管理单元,大小为 16KB。 - 行(Row)
页中存储的数据行,具体格式由 行格式(ROW_FORMAT) 决定。
二、索引组织表(Clustered Index)
InnoDB 表数据的存储方式:
- InnoDB 表是 索引组织表(Index-Organized Table,IOT),即 数据按照主键顺序存放在聚簇索引(Clustered Index)中。
- 表数据即索引的一部分:
- 每个 InnoDB 表 必须有主键(如果没有定义,系统会隐式创建一个 ROW_ID)。
- 主键索引(聚簇索引)中的叶子节点存储整行数据。
聚簇索引的特点:
- 数据按照 主键顺序 存储。
- 叶子节点存放完整行记录。
- 一个表只有 一个聚簇索引。
示意图:
Clustered Index (B+ Tree)
├── Root Page
│ └── Branch Page
│ └── Leaf Page → \[row1, row2, row3, ...] (完整行数据)
三、二级索引(Secondary Index)
- 二级索引的 叶子节点 不存储整行数据,只存储:
- 索引列值
- 对应的主键值(row_id)
- 查询时如果二级索引不能覆盖查询列,需要回表(回到聚簇索引查完整数据),称为 回表操作。
示意图:
Secondary Index (B+ Tree)
├── Root
│ └── Branch
│ └── Leaf → \[index\_column\_value, primary\_key]
四、InnoDB 的页结构(Page Structure)
每个页(Page)大小固定为 16KB,主要用于存储索引和数据。
页的结构如下:
+---------------------+
\| File Header (38B) |
\| Page Header (56B) |
\| Infimum & Supremum |
\| User Records |
\| Free Space |
\| Page Directory |
\| File Trailer (8B) |
+---------------------+
- File Header:页的通用信息,如页号、校验和。
- Page Header:页类型、记录数等。
- Infimum & Supremum:页内的最小/最大虚拟记录。
- User Records:实际用户数据。
- Free Space:空闲空间,用于插入新记录。
- Page Directory:指向记录的槽位,用于快速定位。
- File Trailer:页的完整性校验。
五、InnoDB 行格式(Row Format)
行格式决定了数据在页中的存储方式,常见的行格式有:
行格式 | 特点 |
---|---|
COMPACT | 默认行格式,数据紧凑存放,字段长度 + 数据值。 |
REDUNDANT | 旧版本使用,字段信息存储冗余。 |
DYNAMIC | 大字段(TEXT/BLOB)只存放 20B 指针,实际数据放在溢出页。 |
COMPRESSED | 压缩页数据,提高存储效率。 |
行记录结构:
\[变长字段长度列表]\[NULL 值列表]\[记录头信息]\[列数据]
六、InnoDB 数据存储示意图
表空间 (.ibd 文件)
↓
段 (数据段 / 索引段)
↓
区 (1MB)
↓
页 (16KB)
↓
行 (行格式存储)
七、InnoDB 表存储的关键特性
- 行级锁:基于索引实现。
- 事务支持:通过 Undo Log 回滚、Redo Log 持久化。
- MVCC:通过 Undo Log 提供一致性读。
- 数据页缓存:Buffer Pool 提升性能。
八、面试高频问答
Q1:InnoDB 为什么是索引组织表?
- 因为 InnoDB 聚簇索引的叶子节点存储整行数据,表数据与索引存储在一起。
Q2:聚簇索引和二级索引区别?
- 聚簇索引:叶子节点存储完整行数据。
- 二级索引:叶子节点存储索引列和主键,需要回表。
Q3:InnoDB 的页大小是多少?
- 默认 16KB,可以配置(但常用 16KB)。
Q4:大字段 TEXT/BLOB 如何存储?
- 在 DYNAMIC 行格式下,字段只存储 20B 指针,实际数据存储在溢出页。
Q5:为什么建议 InnoDB 表必须有主键?
- 因为聚簇索引基于主键,如果没有主键,InnoDB 会自动创建隐藏的 row_id,占用空间且影响性能。
九、总结
存储单位 | 大小 |
---|---|
页(Page) | 16KB |
区(Extent) | 1MB(64 页) |
InnoDB 采用 B+ 树 组织数据,表是索引组织表,聚簇索引的叶子节点存放整行数据,二级索引存储主键,实现高效查询。