InnoDB数据存储结构
InnoDB数据存储结构
页内部结构
名称 | 占用大小 | 说明 |
---|---|---|
File Header | 38字节 | 文件头·、描述页的信息 |
PageHeader | 56字节 | 页头,页的状态信息 |
Infimum+Supremum | 26字节 | 最大和最小记录 |
User Recordes | 不确定 | 用户记录,存储行记录内容 |
FreeSpace | 不确定 | 空闲记录 |
PageDirectory | 不确定 | 页目录,存储用户记录的相对位置 |
File Trailer | 8字节 | 文件尾 |
行格式
修改行格式命令
1 | alter table example row_format=compact; |
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 | CREATE TABLE varchar_size_demo( |
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+树的叶子节点和非叶子节点进行了区别对待,也就是说叶子节点有自己独有的区,非叶子节点也有自己独有的区。存放叶子节点的区的集合就算是一个段,存放非叶子节点的区的集合也算是一个段。也就是说一个索引会生成两个段,一个叶子节点段,一个是非叶子节点段
数据段、索引段、回滚段