物理数据结构
数据页
每个数据页大小固定16KB,当加载数据到内存时,都是以数据页为单位加载一页或者多页的。当数据从内存写回磁盘时,也是以数据页为单位进行的:

可以给数据库中的表指定行存储格式。
> CREATE TABLE table_name(column, ……) ROW_FORMAT=COMPACT;
> ALERT TABLE table_name ROW_FORMAT=COMPACT;
每行数据在磁盘文件里存储时,其组成部分如下。
变长字段 + NULL值列表 + 数据头 + 实际数据值。
定长字段直接存储值,不会有附加信息。
变长字段
相邻两行数据,在磁盘里是挨着存储的,写入时保存变长字段的实际长度值,如0x05
。
读取时,会附带读取一些字段额外信息,多个变长字段附加信息是逆序存储的,如hello hell he
的附加信息为0x02 0x04 0x05
。
NULL值列表
对于所有的NULL
值,不使用字符串,而以二进制的bit
位来存储:如果bit
位值1说明是NULL
,否则为0。
数据头
每行数据存储时,都有40个bit
位的数据头,用来描述该行数据。
第1、2位:预留位,无任何意义。
第3位:
delete_mask
,表示该行数据是否被删除。第4位:
min_rec_mask
,标记B+树里每一层非叶子节点里的最小值。第5~8位:共4位,
n_owned
,该行数据的所有者。第9~21位:共13位,
heap_no
,标记当前行数据在记录堆里的位置。第22~24位:共3位,
record_type
,数据类型,0为普通,1为B+树非叶子节点,2为最小值数据,3为最大值数据。第25~40位:共16位,指向下一条数据的指针。

实际数据值
真实的数据值不是直接以字符串的方式存储在磁盘中的,而是按数据库指定的字符集编码来存储的,会在真实数据部分,加入一些隐藏字段。
DB_ROW_ID
:唯一行标志。DB_TRX_ID
:事务ID,指明这是哪条事务处理的数据。DB_ROLL_PTR
:回滚指针,用来进行事务回滚。
例如:0x08 0x05 00000101 0000000000000000000010000000000000011001 00000000094C
00000000032D
EA000010078E
616161 636320 62626262
标记部分为隐藏字段值。
行溢出
行溢出是指当一行数据大小超过数据页(16KB)大小的时,用多个数据页来存储余下的数据。

数据页的组成
文件头部:38字节。
数据页头:56字节。
最大记录&最小记录:26字节。
多个数据行:不固定。
空闲区域:不固定。
数据页目录:不固定。
文件尾部:8字节。

当数据库中还没有数据时,空数据页会被加载到内存的缓存页,在缓存页中插入一条数据(缓存页与数据页是等同的),可以一直往里插入数据,直到空闲区域都耗尽,就意味着页满了。
缓存页被更新时,它在LRU
链表、flush
链表里的位置会不断变动,最终会被写回到磁盘。

表空间及数据区
MySQL创建表的时候,在磁盘上都会对应着表名.ibd
这样的一个磁盘数据文件。表空间的磁盘里,会包含很多数据页,但由于数据页过多不便于管理,就引入了数据区(extent
)的概念。
一个数据区管理连续的64个数据页,因此一个数据区 = 数据页(16KB) × 64 = 1MB,256个数据区被划分为一个组(256MB)。
表空间的第一组数据区的第一个数据区的前3个数据页,内容都是固定的。
FSP_HDR
数据页:存放表空间及该组数据区的属性。IBUF_BITMAP
数据页:存放该组数据页的所有insert buffer信息。INODE
数据页:存放一些特殊信息。
其他各组数据区的第一个数据区的头两个数据页,也都用来存放特殊信息。

小结
创建表的时候物理磁盘上就对应创建
表名.ibd
的表空间文件。一个表空间包含若干数据页(16KB),为了便于管理,引进数据区的概念。
数据区 = 64 × 数据页,数据区组 = 256 × 数据区。
磁盘上的数据区与内存
Buffer Pool
的缓存页是完全对应的,Buffer Pool
默认128MB,等同于128个数据区,或者半个数据区组的大小。Buffer Pool
中有缓存页及其对应的描述文件,同时有free
、LRU
、flush
这3种链表及一些元数据。启动时,MySQL会将空的数据页加载到缓存中,同时将这些缓存页组成
free
链表和LRU
链表(通过预读机制或者全表扫描加载的缓存页都会进入到LRU
链表的冷数据区域)。当插入数据时,依据所在的表空间的数据区的数据页,往缓存页中写入数据。
free
链表删除相应缓存页。LRU
链表(如果是加载该缓存页的1s后)则将处于冷数据区域的缓存页移动到热数据区域的头部。同时
flush
链表也加入指向该缓存页描述数据块的指针节点。后台
I/O
进程会定时扫描LRU
链表冷数据区域的尾部及flush
链表,将一批缓存页数据写入磁盘中。此时这些缓存页的空间将被释放,以便存储新的数据,同时将它们加入到
free
链表中。
感谢支持
更多内容,请移步《超级个体》。