目录
1.绪论
当我们插入的一条数据的时候,mysql为了做持久化,是将数据存储在磁盘中的。如果mysql每次只查询一条数据,这样效率太低。所以mysql每次从磁盘中读取数据是以页为单位的,每页大小为16kb。而一页数据包含多条记录,接下来我们来看看Mysql中记录是如何存储的。
2.InnoDB的记录格式分类
innodb有4种存储记录的格式,分别是redundant,compact,dynamic和compress。其中,redundant格式是5.0之前的一种格式,现在基本上已经弃用。Mysql5.7中默认的行记录格式是dynamic,dynamic和compress与compact的格式相似。所以,这里主要介绍一下compact的格式。
3.compact格式
3.1 基本组成
compact记录格式由3部分组成,分别是记录额外信息,隐藏列,实际数据。如下:
接下来我们来看看这3部分的内容。
3.2 记录额外信息
3.2.1 记录额外信息组成
记录额外信息由3部分组成,分别是变成字段长度列表,null值列表,记录头信息:
3.2.2 变成字段长度列表
1.用来记录该条记录里面的变成字段的长度,并且采用倒序排序。
2.如果某个字段不是变成字段,其长度不会出现在变长字段列表里面。
3.这里变成字段,指的不一定是varchar(n),text,blob这种字符长度是可以改变的字段,也可以是char(m)但是采用变长编码(比如UTF8:1-3个字节,UTF8mb4:1-4个字节)格式的字段。综上,变长字段指的是字节可变的字段。
举例如下:
注:这里为什么采用倒序排序呢?原因是在mysql的页中会有多条记录,每个记录通过记录头信息里面的next_record指针指向下一条记录,所以在遍历记录的时候,首先获取到记录的next_record的位置。如果采用倒序排序,以next_record的位置向两边扩展,就能够得变长字段的长度和数据,读取更加方便。
3.2.3 null值列表
1.在compact记录格式中,null值并没有占据存储空间,而是记录在null值列表中,如果该记录的某列值为null,null值列表变为1,否者为0。
2.null值列表也采用和数据的倒序存储。
3.如果某个列一定不为null,便不会出现在null值列表中。
4.null值列表大小如果不是8位的倍数,高位补0。
3.2.4 记录头信息
记录头信息,包含32位,我们来看看有何作用。
名称 | 大小 | 描述 |
预留位1 | 1 | 没使用 |
预留位2 | 1 | 没使用 |
delete_mask | 1 | 记录是否被删除,在页中的记录数据时采用懒删除的模式,每次删除会将该标志位设置为1 |
min_rec_mask | 1 | B+树非叶子节点的最小的一条记录,该索引设置为1 |
n_owned | 4 | 表示当前记录拥有的记录数,B+树每个节点可以存放多个元素,对于第一个元素,n_owned就是该节点后面的所有元素。所以该节点的阶为n_owned+1 |
heap_no | 4 | 在记录堆中的位置信息,每页数据在插入的时候会采用顺序插入的方式,便是该条记录在整页中是第几条顺序 |
record_type | 3 | 表示当前记录的类型,0 表示普通记录,1 表示B+树非叶子节点记录,2 表示最小记录,3 表示最大记录 |
next_record | 16 | 执向下一条消息的指针 |
这里面最重要的一个属性就是next_record,通过它将记录堆中的索引从小到大组成一个链表。
3.3 实际记录
3.3.1 溢出页
前面说过,mysql存储数据的每页为16kb,即16384个字节,而且mysql要求每页至少存储2条记录,所以当记录超过16384个字节的时候,便会采用额外的页来记录数据,这种页称为溢出页。
3.3.2 varchar最多可以储存多少个字符的数据
mysql中要求,除了text和blob这种类型的数据外,其他类型总的长度(包括隐藏列和记录的额外信息)不能超过65534个字节。假设所采用的编码集占用的最大字节数为n(比如gbk为2,utf8为3),则最多占用的字符数为m=(65534-额外部分信息)/n。
4.其他记录格式和compact的不同
dynamic:dynamic主要在存储溢出页的时候,只存储溢出页的指针,没有存储该列的数据。
compress:compress会采用压缩算法对数据进行压缩。