MySQL 数据存储结构

在数据库中存储的数据,最终需要都需要落到磁盘上进行持久化保存。这里对 MySQL 的数据存储结构进行分析。

MySQL 中,表数据由存储引擎负责存取。下面的数据存储结构以 InnoDB 存储引擎为准。在 InnoDB 存储引擎中,数据保存在 /var/lib/mysql/ 目录下,对于创建的每个数据库,会用数据库名称创建一个同名目录。该目录中,包括 db.opt 文件存储数据库的默认字符编码等信息。另外,为每个数据表创建同名的 frm 和 ibd 两个文件。frm 文件存储数据表的元数据,包括表结构等信息。ibd 文件存储数据表的表数据,也称为表空间文件。

对表空间文件,可以分为段(Segment)、区(Extent)、页(Page)、行(Row)四个从大到小的层级。

Row(行):行级别存储数据库中的一条数据记录(行)。

Page(页):页是数据库进行磁盘读写的基本单位,默认大小为 16KB ,它也是存储空间连续的最大保证。

Extent(区):当表中的数据量较大时,会按区分配空间,每个区大小 1MB ,以此来提高存储的连续性。

Segment(段):可分为数据段(存储叶节点)、索引段(存储非叶节点)、回滚段等。

对于数据表中的行,主要有 Redundant、Compact、Compressed、Dynamic 四种行数据存储格式,MySQL 5.7 后,默认使用的行格式即为 Dynamic 。Compressed、Dynamic 的数据行格式与 Compact 相似,下面就对 Compact 行格式进行分析。

Compact 行格式可通过下面图的来表示:

变长字段长度列表:存储可变长度的字段中值的长度,而 NULL 值不需要在这里进行记录。根据字段的最大长度,每个字段占用 1 个或 2 个字节。为了提高内存局部性,字段顺序与数据的值列表顺序相反。当没有需要记录的字段长度时,变长字段长度列表就不需要存在。

NULL 值列表:存储可空字段是否为空的标记。每个可空字段仅占用一个二进制位,这些二进制位对齐到字节。同样的,字段顺序与数据的值列表顺序相反。当没有需要记录的 NULL 值记录时,NULL 值列表就不需要存在。

记录头信息:其中存储包括 delete_mask、next_record、record_type 等数据。delete_mask 为数据删除标记;next_record 记录下一条记录的位置(数据链表);record_type 为数据的记录类型,0-普通记录,1-非叶节点,2-最小记录,3-最大记录。

row_id、trx_id、roll_ptr 则用于 ACID 特性的实现。这些字段加上数据列值就构成真实数据。

此外,除 TEXT、BLOB 这些大对象及隐藏字段外,每行最多占用 65535 字节(包括变长字段长度列表、NULL 值列表、数据列值)。

当行数据超出页的大小时,数据将转移到溢出页,而数据页中只存放溢出页的地址。

参考资料