器→工具, 工具软件, 术→技巧, 研发

MySQL InnoDB行记录格式

钱魏Way · · 962 次浏览
!文章内容如有错误或排版问题,请提交反馈,非常感谢!

在早期的 InnoDB 版本中,由于文件格式只有一种,因此不需要为此文件格式命名。随着 InnoDB 引擎的发展,开发出了不兼容早期版本的新文件格式,用于支持新的功能。为了在升级和降级情况下帮助管理系统的兼容性,以及运行不同的 MySQL 版本,InnoDB 开始使用命名的文件格式。

  • Antelope: 先前未命名的,原始的 InnoDB 文件格式。它支持两种行格式:COMPACT 和 REDUNDANT。6 的默认文件格式。可以与早期的版本保持最大的兼容性。不支持 Barracuda 文件格式。
  • Barracuda: 新的文件格式。它支持 InnoDB 的所有行格式,包括新的行格式:COMPRESSED 和 DYNAMIC。与这两个新的行格式相关的功能包括:InnoDB 表的压缩,长列数据的页外存储和索引建前缀最大长度为 3072 字节。

ROW_FORMAT 值:

ROW_FORMAT 支持索引前缀 独立表空间压缩 系统表空间压缩
COMPRESSED 3072 字节 支持 不支持
DYNAMIC 3072 字节 不支持 不支持
COMPACT 768 字节 不支持 支持
REDUNDANT 768 字节 不支持 支持

在 mysql 5.7.9 及以后版本,默认行格式由 innodb_default_row_format 变量决定,它的默认值是 DYNAMIC,也可以在 create table 的时候指定 ROW_FORMAT=DYNAMIC。用户可以通过命令 SHOW TABLE STATUS LIKE ‘table_name’ 来查看当前表使用的行格式,其中 row_format 列表示当前所使用的行记录结构类型。

如果要修改现有表的行模式为 compressed 或 dynamic,必须先将文件格式设置成 Barracuda:set global innodb_file_format=Barracuda;,再用 ALTER TABLE tablename ROW_FORMAT=COMPRESSED; 去修改才能生效。

InnoDB 行存储

InnoDB 存储引擎和大多数数据库一样(如 Oracle 和 Microsoft SQL Server 数据库),记录是以行的形式存储的。这意味着页中保存着表中一行行的数据。这些页以树形结构组织,这颗树称为 B 树索引。表中数据和辅助索引都是使用 B 树结构。维护表中所有数据的这颗 B 树索引称为聚簇索引,通过主键来组织的。聚簇索引的叶子节点包含行中所有字段的值,辅助索引的叶子节点包含索引列和主键列。

行记录最大长度

  • 页大小(page size)为 4KB、8KB、16KB 和 32KB 时,行记录最大长度(maximum row length)应该略小于页大小的一半
    • 默认页大小为 16KB,行记录最大长度应该略小于 8KB,因此一个 B+Tree 叶子节点最少有 2 个行记录
  • 页大小为 64KB 时,行记录最大长度略小于 16KB

CHAR(N)与 VARCHAR(N)

N 指的是字符长度,而不是 Byte 大小,在不同的编码下,同样的字符会占用不同的空间,如 LATIN1(定长编码)和 UTF8(变长编码)

变长列

在 InnoDB 中,变长列(variable-length column)可能是以下几种情况

  • 长度不固定的数据类型,例如 VARCHAR、VARBINARY、BLOB、TEXT 等
  • 对于长度固定的数据类型,如 CHAR,如果实际存储占用的空间大于 768 Byte,InnoDB 会将其视为变长列
  • 变长编码下的 CHAR

行溢出

当行记录的长度没有超过行记录最大长度时,所有数据都会存储在当前页

当行记录的长度超过行记录最大长度时,变长列(variable-length column)会选择外部溢出页(overflow page,一般是 Uncompressed BLOB Page)进行存储

  • Compact+Redundant:保留前 768 Byte 在当前页(B+Tree 叶子节点),其余数据存放在溢出页。768 Byte 后面跟着 20 Byte 的数据,用来存储指向溢出页的指针
  • Dynamic+Compressed:仅存储 20 Byte 数据,存储指向溢出页的指针,这时比 Compact 和 Redundant 更高效,因为一个 B+Tree 叶子节点能存放更多的行记录

Redundant

MySQL 5.0 之前的 ROW_FORMAT格式

字段偏移列表 记录头信息 ROWID TransactionID RollPointer 列 1 列 n

字段偏移列表

  • 按照列的顺序逆序放置
  • 列长度小于 255 Byte,用 1 Byte 存储
  • 列长度大于 255 Byte,用 2 Byte 存储

记录头信息

名称 大小(bit) 描述
() 1 未知
() 1 未知
deleted_flag 1 该行是否已被删除
min_rec_flag 1 如果该行记录是预定义为最小的记录,为 1
n_owned 4 该记录拥有的记录数,用于 Slot
heap_no 13 索引堆中该条记录的索引号
n_fields 10 记录中列的数量,一行最多支持 1023 列
1byte_offs_flag 1 偏移列表的单位为 1 Byte 还是 2 Byte
next_record 16 页中下一条记录的相对位置
Total 48 (6Byte) nothing

隐藏列

  • ROWID:没有显式定义主键或唯一非NULL的索引时,InnoDB会自动创建6Byte的ROWID
  • TransactionID:事务ID
  • RollPointer:回滚指针列

Compact

MySQL 5.0引入,MySQL 5.1默认ROW_FORMAT对比Redundant

  • 减少了大约20%的空间
  • 在某些操作下会增加CPU的占用
  • 在典型的应用场景下,比Redundant快

格式

变长字段长度列表 NULL标志位 记录头信息 ROWID TransactionID RollPointer 列1 列n

变长字段长度列表

  • 条件
    • VARCHAR、BLOB等
    • 变长编码(如UTF8)下的CHAR
  • 放置排序:逆序
  • 用2Byte存储的情况:需要用溢出页;最大长度超过255Byte;实际长度超过127Byte

NULL标志位

  • 行记录中是否有NULL值,是一个位向量(Bit Vector)
  • 可为NULL的列数量为N,则该标志位占用的CEILING(N/8)Byte
  • 列为NULL时不占用实际空间

记录头信息

名称 大小(bit) 描述
() 1 未知
() 1 未知
deleted_flag 1 该行是否已被删除
min_rec_flag 1 如果该行记录是预定义为最小的记录,为1
n_owned 4 该记录拥有的记录数,用于Slot
heap_no 13 索引堆中该条记录的索引号
record_type 3 记录类型,000(普通),001(B+Tree节点指针),010(Infimum),011(Supremum)
next_record 16 页中下一条记录的相对位置
Total 40 (5Byte) nothing

Dynamic

MySQL版本是5.7,它的默认⾏格式就是Dynamic。

dynamic行格式,列存储是否放到off-page页,主要取决于行大小,它会把行中最长的那一列放到off-page,直到数据页能存放下两行。TEXT/BLOB列<=40bytes时总是存放于数据页。这种方式可以避免compact那样把太多的大列值放到B-tree Node,因为dynamic格式认为,只要大列值有部分数据放在off-page,那把整个值放入都放入off-page更有效。

Compressed

compressed物理结构上与dynamic类似,但是对表的数据行使用zlib算法进行了压缩存储。在longblob列类型比较多的情况下用,可以降低off-page的使用,减少存储空间(一般40%左右),但要求更高的CPU,buffer pool里面可能会同时存储数据的压缩版和非压缩版,所以也多占用部分内存。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注