MySQL InnoDB 记录(行)的完整字段详解
在 InnoDB 存储引擎中,一条记录的完整结构不仅包含用户定义的列,还包含多个 系统隐藏字段。这些隐藏字段是 InnoDB 实现事务(ACID)、多版本并发控制(MVCC)和索引机制的核心。以下是逐条解析:
1. 用户定义的列(User Columns)
即表结构中用户明确定义的字段,例如
CREATE TABLE users (
id INT PRIMARY KEY, -- 主键列
name VARCHAR(50), -- 普通列
age INT, -- 普通列
created_at TIMESTAMP -- 普通列
);
- 存储内容:用户插入或更新的具体数据。
- 物理存储:根据行格式(如 COMPACT、DYNAMIC)压缩存储。
2. 系统隐藏字段(System Columns)
InnoDB 自动为每条记录添加以下隐藏字段:
2.1 DB_ROW_ID(行ID)
- 作用:
当表未定义主键时,InnoDB 自动生成一个 6 字节的隐式主键(DB_ROW_ID)。
若表有自定义主键,则此字段不生成。 - 特点:
全局单调递增,用于唯一标识记录。
用户无法直接访问,但可通过特殊工具(如 InnoDB 表空间解析工具)查看。
2.2 DB_TRX_ID(事务ID)
- 作用:
记录最后一次修改该行数据的事务ID(即 trx_id)。
用于 MVCC,判断数据版本对当前事务的可见性。
大小:6 字节。 - 示例:
事务 A(trx_id=100)更新一行后,该行的 DB_TRX_ID 被标记为 100。
2.3 DB_ROLL_PTR(回滚指针)
- 作用:
指向 undo 日志中旧版本数据的指针,用于实现事务回滚和 MVCC。
通过回滚指针,可以追溯数据的历史版本。
大小:7 字节。 - 示例:
事务 B 查询某行时,若该行的 DB_TRX_ID 大于当前事务ID,则通过 DB_ROLL_PTR 找到可见的旧版本。
2.4 删除标记(Delete Flag)
- 作用:
标记该行是否被删除(逻辑删除)。
InnoDB 的 DELETE 操作不会立即物理删除数据,而是设置此标记。 - 清理时机:
由 Purge 线程在事务提交后清理标记为删除的行。
3. 记录头信息(Record Header)
每条记录还包含一个 记录头,用于管理记录的元信息,主要字段如下:
- 3.1 预留位(预留字段)
作用:用于未来扩展,通常无实际用途。 - 3.2 删除标记(Delete Flag)
作用:同系统隐藏字段中的删除标记,标识该行是否被逻辑删除。 - 3.3 最小事务ID(Min Transaction ID)
作用:在部分行格式中,记录该行可见的最小事务ID(用于优化 MVCC 判断)。 - 3.4 记录类型(Record Type)
作用:标识记录的类型,例如:- 0:普通记录。
- 1:B+ 树非叶子节点(索引节点)。
- 2:伪记录(Infimum/Supremum,表示页中的最小和最大虚拟记录)。
- 3.5 下一记录指针(Next Record Pointer)
作用:指向页中下一条记录的物理位置,用于实现记录的链式存储。
4. 溢出页指针(对于大字段)
当记录中包含大对象(如 BLOB、TEXT 或超长 VARCHAR)时:
行溢出(Row Overflow):
数据主体存储在数据页中,超出页大小的部分存储在溢出页(Off-page)。
记录中保留 20 字节的指针,指向溢出页的地址。
5. 记录的物理存储示例
以 COMPACT 行格式为例,一条记录的完整结构如下:
| 记录头(5字节) | 用户列1 | 用户列2 | ... | DB_ROW_ID(6字节) | DB_TRX_ID(6字节) | DB_ROLL_PTR(7字节) |
总大小:记录头 + 用户列 + 隐藏字段 + 溢出页指针(若有)