1.数据存储格式

  1. CREATE TABLE table_name (columns) ROW_FORMAT=COMPACT
  2. ALTER TABLE table_name ROW_FORMAT=COMPACT

可以在建表的时候,指定一个行存储的格式,后续也可以修改存储的格式。这里指定一个COMPACT行存储格式。在这种格式下,每一行数据实际存储的格式类似下面这样:
变长字段的长度列表,null值列表,数据头,column01的值,column02的值,column0n的值.....

2.变长字段存储

在MySQL中有一些字段的长度是变长的,比如VARCHAR(10)字段,有可能是“hello”,也可能是“a”。
假设现在有一行数据,字段类型分别是VARCHAR(10),CHAR(1),CHAR(1),这一行的数据是:hello a a,
第一个字段的值是“hello”,后面两个字段都是一个字符“a”;另一行数据,同样是这几个字段,第一个字段的值是“hi”,后面两个字段也是“a”。假设两条数据写入磁盘文件里,两行数据是挨在一起的,那么在磁盘中存储的格式是:hello a a hi a a
问题产生:因为不知道一行数据每个字段的长度,所以无法去读取行数据。
实际上,在存储“hello a a”这行数据的时候,会带上一些额外信息,首先就是变长字段的长度列表。“hello”的长度是5,十六进制就是0x05,这行数据在磁盘文件里存储的格式实际上是:0x05 null值列表 数据头 hello a a
假设有两行数据,还有一行数据可能就是:0x02 null值列表 数据头 hi a a,两行数据放在一起存储在磁盘文件里,存储格式是: 0x05 null值列表 数据头 hello a a 0x02 null值列表 数据头 hi a a
在读取“hello a a”这行数据时,会发现第一行数据的开头有一个变长字段的长度列表,会读取到一个0x05这个十六进制的数字,发现第一个变长字段为5,于是按照长度为5,读取第一个字段的值,就是“hello”;后两个字段都是CHAR(1),固定长度都是1,于是就按照长度1读取数据,最终读出来“hello a a”这一行数据。

3.NULL字段存储

对于所有的NULL值,是通过二进制的bit位来存储的。
数据在磁盘上的存储结构:变长字段长度列表 NULL值列表 头信息 column1=value1 column2=value2 ... columnN=valueN
NULL值列表:允许值为NULL的字段,就会有一个二进制bit位的值,如果bit值是1说明是NULL,如果bit值是0说明不是NULL。
eg:jack NULL m NULL xx_school 对应 1010

4.数据头

每一行数据存储,都有40个bit位的数据头,不同数据头都是用来描述这行数据的一些状态和附加信息的。
第一个和第二个bit位都是预留位,没有任何含义;然后有一个bit位是delete_mask,标识这行数据是否被删除,也就是说,删除一行数据的时候,并不是立马从磁盘中删除了…

5.行溢出

每一行数据都是放在一个数据页的,这个数据页默认的大小是16KB,如果一行数据的大小大于16KB,就会出现行溢出。
出现行溢出的时候,实际上会在当前数据页存储部分数据,同时包含一个20字节的指针,指向其他数据页,剩下部分的数据就会存储在指针指向的数据页中。
05_MySQL物理数据存储格式 - 图1

6.数据页存储结构

一个数据页拆分为很多部分,大体上分为文件头、数据页头、最小记录和最大记录、多个数据行、空闲空间、数据页目录、文件尾部。
05_MySQL物理数据存储格式 - 图2
其中文件头占据了38个字节,数据页头占据了56个字节,最大记录和最小记录占据了26个字节,数据行区域大小和空闲区域、数据页目录大小是不固定的,文件尾部占据8个字节。
如果一开始数据页中没有数据,那么就没有“多个数据行”区域。如果“空闲区域”耗尽了,就没有“空闲区域”了。

7.表空间与数据区

我们平时创建的表,都有一个表空间的概念,在磁盘上对应“表名.ibd”文件。
一个表空间中会有多个数据页,如果一个表空间包含的数据页太多了,不便于管理,所以引入了数据区的概念。
一个数据区对应连续的64个数据页,每个数据页大小是16kb,一个数据区就是1mb,256个数据区被划分一个组。
表空间的第一组数据区的第一个数据区的前三个数据页都是固定的,里面存放了一些描述性数据。比如FSP_HDR这个数据页,它里面存放了表空间和这一组数据区的一些属性;IBUF_BITMAP数据页,存放的是这一组数据页所有的insert buffer的一些信息。
表空间的其他各组数据区,每一组数据区的第一个数据区的前两个数据页,都是存放特殊信息的。比如XDES数据页是来存放着一组数据区的相关属性的。
当我们执行crud操作时,就是从磁盘上的表空间的数据文件里,加载一些数据页出来到buffer pool的缓存页。