InnoDB记录结构深度解析
一、InnoDB存储基础单元:页(Page)
- 页大小:默认16KB,是InnoDB磁盘与内存交互的基本单位。
- 页作用:所有数据读写操作以页为单位,避免频繁磁盘IO,提升性能。
二、行格式(Row Format)
InnoDB提供4种行格式:Compact、Redundant、Dynamic、Compressed。核心区别在于数据存储方式和溢出处理机制。
三、核心行格式详解
1. Compact行格式

结构组成:
- 变长字段长度列表(Variable-Length Field Length List)
- 逆序存储:所有变长字段(如VARCHAR)的真实数据长度按列顺序逆序存放。
- 长度表示规则:
- 若最大长度 ≤ 255字节,用1字节表示实际长度。
- 若最大长度 > 255字节,根据实际长度选择1或2字节(L≤127用1字节,L>127用2字节)。
NULL值列表(NULL Value List)
- 二进制位图:每个允许NULL的列对应1位(1表示NULL,0非NULL),按列逆序排列。
- 字节对齐:不足8位补0,例如3个NULL列用1字节(二进制高位补0)。
记录头信息(Record Header)
- 固定5字节,关键标志位:
delete_mask:标记记录是否被删除。next_record:下一条记录的相对位置(链表结构)。record_type:记录类型(0-普通,1-B+树非叶节点,2-最小记录,3-最大记录)。
- 真实数据(Real Data)
- 隐藏列:自动添加
row_id(可选)、transaction_id(事务ID)、roll_pointer(回滚指针)。 - CHAR(M)存储:
- 隐藏列:自动添加
- 定长字符集(如ascii):固定占用M×字符字节,不足填充空格。
- 变长字符集(如utf8):长度存入变长字段列表,至少占用M字节。
相比redundant的改进:
- Compact仅存储非NULL变长字段的实际字节长度(逆序排列),redundant存储所有字段偏移地址
- Compact使用位图标记NULL列(每列1位),例如3个允许NULL的列仅需1字节存储状态。Redundant则通过偏移量高位标记NULL,每个允许NULL的列需额外占用偏移量空间
- Compact头信息5字节 包含
delete_mask、record_type等核心字段,支持更细粒度的记录管理。redundant头信息6字节,额外包含n_field(列数量)和1byte_offs_flag(偏移量字节数标识),缺少record_type字段 - 发生行溢出:Compact保留768字节前缀,redundant无优化机制直接存额外页导致更多空间碎片
2. Redundant行格式(兼容旧版本)

核心差异:
- 字段长度偏移列表:所有列(含隐藏列)的结束位置偏移量,逆序存储,通过差值计算列长。
- NULL处理:偏移量首比特标记NULL,定长列NULL仍占空间(填充0x00),变长列不占。
- 记录头信息:
- 6字节,含
n_field(列数量)和1byte_offs_flag(偏移量字节数标记)。 - 无
record_type字段。
- 6字节,含
3. Dynamic与Compressed行格式
- Dynamic:类似Compact,但所有溢出数据存于溢出页,仅保留20字节指针。
- Compressed:在Dynamic基础上增加页级压缩,减少存储空间。
适用场景差异
Dynamic的优势场景:
- 适用于超长变长字段(如TEXT/BLOB),溢出数据占比高时,减少原始页空间浪费。
- 不适用场景:若记录长度普遍小于页容量(16KB),Dynamic与Compact性能差异不大。
Compressed的优势场景:
- 适合存储成本敏感、读多写少的场景(如日志归档、历史数据存储)。
- 不适用场景:OLTP系统(高频更新)、或CPU资源紧张时,压缩开销可能成为瓶颈。
四、行溢出处理机制
- 溢出条件:单行数据超过页大小(16KB)阈值(约768字节后存溢出页)。
- 溢出页管理:
- 仅保留前缀数据(768字节)在本页,剩余数据存入溢出页。
- 通过指针链接溢出页,保证主页数据连续性。
五、关键对比与选型建议
| 特性 | Compact | Redundant | Dynamic |
|---|---|---|---|
| 变长字段存储 | 仅变长字段长度列表 | 全字段偏移列表 | 类似Compact |
| NULL处理 | 独立NULL列表 | 偏移量首比特标记 | 同Compact |
| 溢出处理 | 部分保留前缀 | 同Compact | 全部存溢出页 |
| 空间效率 | 高 | 较低 | 高 |
| 适用场景 | 常规OLTP | 旧系统兼容 | 大字段频繁更新 |
| 格式 | 适用场景 | 不适用场景 |
|---|---|---|
| Compact | 通用场景,短记录为主,兼容旧版本 | 大字段频繁访问,存储成本敏感 |
| Dynamic | 超长变长字段(TEXT/BLOB),溢出数据占比高 | 记录普遍短小,需避免溢出页I/O开销 |
| Compressed | 读多写少,存储成本敏感(如归档数据) | 高频写入、CPU资源紧张、OLTP系统 |
六、总结
- 行格式选择:默认使用Dynamic(MySQL 5.7+),平衡空间与性能。
- CHAR vs VARCHAR:
- CHAR适合定长数据(如MD5),减少碎片。
- VARCHAR节省空间,但频繁更新可能产生碎片。
- 避免行溢出:大字段(如TEXT/BLOB)建议分离存储或使用压缩。
- NULL优化:尽量使用NOT NULL,减少NULL列表开销。
通过理解InnoDB记录结构,可针对性优化表设计,提升存储效率与查询性能。
