3.4.2 记录头信息(record header)
不同于Compact行格式,Redundant行格式中的记录头信息固定占用6个字节(48位),每位的含义见下表
与Compact行格式的记录头信息对比来看,有两处不同:(下面的解释,了解即可)
Redundant行格式多了n_field和1byte_offs_flag这两个属性。
Redundant行格式没有record_type这个属性。
其中,n_fields:代表一行中列的数量,占用10位,这也很好地解释了为什么MySQL一个行支持最多的列为1023。另一个值为1byte_offs_flags,该值定义了偏移列表占用1个字节还是2个字节。当它的值为1时,表明使用1个字节存储。当它的值为0时,表明使用2个字节存储。
1byte_offs_flag的值是怎么选择的 ?
我们前边说过每个列对应的偏移量可以占用1个字节或者2个字节来存储,那到底什么时候用1个字节,什么时候用2个字节呢?其实是根据该条Redundant行格式记录的真实数据占用的总大小来判断的:
当记录的真实数据占用的字节数值不大于127(十六进制0x7F,二进制01111111)时,每个列对应的偏移量占用1个字节。
当记录的真实数据占用的字节数大于127,但不大于32767(十六进制0x7FFF,二进制0111111111111111)时,每个列对应的偏移量占用2个字节。
有没有记录的真实数据大于32767的情况呢?有,不过此时的记录已经存放到了溢出页中,在本页中只保留前768个字节和20个字节的溢出页面地址。因为字段长度偏移列表处只需要记录每个列在本页面中的偏移就好了,所以每个列使用2个字节来存储偏移量就够了。
大家可以看出来,Redundant行格式还是比较简单粗暴的,直接使用整个记录的真实数据长度来决定使用1个字节还是2个字节存储列对应的偏移量。只要整条记录的真实数据占用的存储空间大小大于127,即使第一个列的值占用存储空间小于127,那对不起,也需要使用2个字节来表示该列对应的偏移量。简单粗暴,就是这么简单粗暴(所以这种行格式有些过时了)。
为了在解析记录时知道每个列的偏移量是使用1个字节还是2个字节表示的,Redundant行格式特意在记录头信息里放置了一个称之为1byte_offs_flag的属性:
Redundant行格式中NULL值的处理
因为Redundant行格式并没有NULL值列表,所以Redundant行格式在字段长度偏移列表中的各个列对应的偏移量处做了一些特殊处理 —— 将列对应的偏移量值的第一个比特位作为是否为NULL的依据,该比特位也可以被称之为NULL比特位。也就是说在解析一条记录的某个列时,首先看一下该列对应的偏移量的NULL比特位是不是为1。如果为1,那么该列的值就是NULL,否则不是NULL。
这也就解释了上边介绍为什么只要记录的真实数据大于127(十六进制0x7F,二进制01111111)时,就采用2个字节来表示一个列对应的偏移量,主要是第一个比特位是所谓的NULL比特位,用来标记该列的值是否为NULL。
但是还有一点要注意,对于值为NULL的列来说,该列的类型是否为定长类型决定了NULL值的实际存储方式,我们接下来分析一下record_test_table表的第二条记录,它对应的字段长度偏移列表如下:
A4 A4 1A 17 13 0C 06
按照列的顺序排放就是:
06 0C 13 17 1A A4 A4
我们分情况看一下:
如果存储NULL值的字段是定长类型的,比方说CHAR(M)数据类型的,则NULL值也将占用记录的真实数据部分,并把该字段对应的数据使用0x00字节填充。
如图第二条记录的c3列的值是NULL,而c3列的类型是CHAR(10),占用记录的真实数据部分10字节,所以我们看到在Redundant行格式中使用0x00000000000000000000来表示NULL值。
另外,c3列对应的偏移量为0xA4,它对应的二进制实际是:10100100,可以看到最高位为1,意味着该列的值是NULL。将最高位去掉后的值变成了0100100,对应的十进制值为36,而c2列对应的偏移量为0x1A,也就是十进制的26。36 - 26 = 10,也就是说最终c3列占用的存储空间为10个字节。
如果该存储NULL值的字段是变长数据类型的,则不在记录的真实数据处占用任何存储空间。
比如record_test_table表的c4列是VARCHAR(10)类型的,VARCHAR(10)是一个变长数据类型,c4列对应的偏移量为0xA4,与c3列对应的偏移量相同,这也就意味着它的值也为NULL,将0xA4的最高位去掉后对应的十进制值也是36,36 - 36 = 0,也就意味着c4列本身不占用任何记录的实际数据处的空间。
除了以上的几点之外,Redundant行格式和Compact行格式还是大致相同的
总结:Redundant行格式和Compact行格式的差异
Redundant 没有了NULL值列表
Redundant 行格式的记录头信息
多了n_field和1byte_offs_flag这两个属性
没有record_type这个属性。
4. 区、段与碎片区
4.1 为什么要有区?
4.2 为什么要有段?
4.3 为什么要有碎片区?
4.4 区的分类
5. 表空间
5.1 独立表空间
你能看到inndb_file_per_table=ON,这意味着每张表都会单独保存一个.ibd文件
5.2 系统表空间
附录:数据页加载的三种方式