InnoDB数据存储结构

页内部结构

名称 占用大小 说明
File Header 38字节 文件头·、描述页的信息
PageHeader 56字节 页头,页的状态信息
Infimum+Supremum 26字节 最大和最小记录
User Recordes 不确定 用户记录,存储行记录内容
FreeSpace 不确定 空闲记录
PageDirectory 不确定 页目录,存储用户记录的相对位置
File Trailer 8字节 文件尾

行格式

修改行格式命令

1
2
3
alter table example row_format=compact;

show table status like 'example'\G

Compact行格式

变长字段长度列表 NULL值列表 记录头信息 row_id trx_id roll_ptr n个数据列

变长字段列表

记录表中使用vachar声明的列实际存储的值的长度大小,例如:第一、三、五列实际长度为:8、4、6,那么长度列表中则记录为060408,逆序顺序

NULL值列表

采用二进制的值表示是否为NULL,1为NULL,0不为NULL

比如第一、二、三列均不为NULL,第四列为NULL,则记录1000,如果第一列设置为NOT NULL或者主键,则无需记录第一列的NULL值情况,100

记录真实的数据

  • row_id

如果我们建表的时候指定了主键或者唯一约束列,那么就没有 row_id 隐藏字段了。如果既没有指定主键,又没有唯一约束,那么 InnoDB 就会为记录添加 row_id 隐藏字段。row_id不是必需的,占用 6 个字节。

  • trx_id

事务id,表示这个数据是由哪个事务生成的。 trx_id是必需的,占用 6 个字节。

  • roll_pointer

这条记录上一个版本的指针。roll_pointer 是必需的,占用 7 个字节

Vachar最多可存储的数据大小

首先与表的定义的字符集有关

如果CHARSET=ASCII最多可以声明65532

1
2
3
CREATE TABLE varchar_size_demo(
c vachar(65532)
) CHARSET=ASCII ROW_FORMAT=COMPACT;

vachar最多可以声明为65535,但是行格式中还需要两个字节的变长长度字段和1个字节的NULL标识符

我们可以知道一个页的大小一般是16KB,也就是16384字节,而一个VACHAR类型的列最多可以存储65533个字节,这样就可能出现一个页放不下一条记录,这种现象就是行溢出

如果一个数据页存不了一条记录,InnoDB 存储引擎会自动将溢出的数据存放到「溢出页」中。在一般情况下,InnoDB 的数据都是存放在 「数据页」中。但是当发生行溢出时,溢出的数据会存放到「溢出页」中。

当发生行溢出时,在记录的真实数据处只会保存该列的一部分数据,而把剩余的数据放在「溢出页」中,然后真实数据处用 20 字节存储指向溢出页的地址,从而可以找到剩余数据所在的页

Compressed 和 Dynamic 这两个行格式和 Compact 非常类似,主要的区别在于处理行溢出数据时有些区别。

这两种格式采用完全的行溢出方式,记录的真实数据处不会存储该列的一部分数据,只存储 20 个字节的指针来指向溢出页。而实际的数据都存储在溢出页中,看起来就像下面这样:

区、段

为什么还要区

B+树的每一层中的页都会形成一个双向链表,如果以页为单位来分配存储空间的话,页的物理存储地址是随机的,读取页时是随机I/O,如果两个页物理地址相距地很远,I/O速度会很慢,所以我们应该尽量让链表中相邻地物理地址也相邻,这样进行范围查询地时候才可以使用所谓地顺序I/O

一个区就是在物理位置上连续的64个页

为什么还有段

InnoDB对B+树的叶子节点和非叶子节点进行了区别对待,也就是说叶子节点有自己独有的区,非叶子节点也有自己独有的区。存放叶子节点的区的集合就算是一个段,存放非叶子节点的区的集合也算是一个段。也就是说一个索引会生成两个段,一个叶子节点段,一个是非叶子节点段

数据段、索引段、回滚段