MySQL深度剖析之数据在磁盘上存储(2021)

一 数据在磁盘上存储格式(row format)

表中的数据在磁盘上存储是有格式的,可以在创建表的时候通过row_format指定,比如MySQL5.0之前的reduntant,MySQL5.0 之后的compact和dynamic,两个差不多,区别在于页面溢出处理上,还有compressed,在dynamic基础上使用了压缩算法,MySQL5.7 默认就是dynamic,我们这里以compact举例子,它格式如图所示:

 

二 变长字段长度列表

MySQL表中有些字段长度不固定,是动态的,比如varchar,而tinyint smallint int bigint float boolean char 长度都是固定的。而数据存储又是紧挨着的,所以怎么样知道哪些数据是一行,哪些数据是哪一个字段的,我们比如表字段和数据是这样的:


那么我们知道bigint占用8字节,int占用4字节,char默认占用1字节,但是对于三个varchar字段却是不知道占用多少字节,所以用一个变长字段长度列表逆序表示字段长度,第一行数据的变长字段长度列表逆序表示:0x04 0x03 0x09, 第二行数据的变长字段长度列表逆序表示:0x04 0x05 0x04。那么这2行数据可以表示为0x04 0x03 0x09 null值列表 头信息 118894019127279619 beautiful men kind 20 F 0x04 0x05 0x04 null值列表 头信息 120095254907979779 good women cool 30 G。

 

三 Null值列表

在表中,有些字段是允许为null值,如果我们在存储时候,将null存储到磁盘,如果很多null,岂不是很浪费磁盘空间,所以通过位来存储,根据字段数量,决定位的长度,但最少都是8位,如果不够8位,即字段长度不够8,则高位用0补齐。并且null值列表也是逆序排序的。

如果可变长字段也允许null值存在,还需要在变长字段长度列表中存储长度为0吗,这是不需要的,变长字段长度列表只是逆序记录不为空的变长字段长度,那怎么才知道这个字段是不是为空的,根据null值列表就知道了,如果对应的可变长字段不为0,则表示有长度,则从变长字段长度列表获取

 

以上图为例,总共6个字段,只有2个字段允许为null, 那么第一行就是01,表示倒数的第一个允许为null字段并不是null,倒数第二个允许为null的字段为null,因为至少要8位,则是00000001,同理对应的第二行null值列表00000011,表示这个两个字段都是null.

因为null值列表存在变长字段情况,所以为null的变长字段在变长字段列表中不存在,所以的第一行变长字段长度列表 0x04 0x04 0x03,第二行是0x05 0x05那么整个数据的存储是这样的: 0x04 0x04 0x03 00000001 头信息118894019127279619 men kind code 20 0x05 0x05 00000011 头信息120095254907979779 women great 30

四 头信息

头信息是一个40位长度比特位,存储着一些额外信息,比如当前行是否已经被删除、下一个记录相对位置、字段数量等等。比如:

 

五 行溢出

我们知道一行数据是放在数据页中的,每一个数据页大小是16KB,如果该行数据超过了16KB,这时候一个数据页存放不下,比如varchar(65535)如果超过65535个字符很可能数据已经超过了16KB,则数据页放不下,这种现象叫做行溢出。常见的容易发生行溢出字段,比如TEXT、BLOB等

怎么解决行溢出呢?

首先:行中的大字段存储一部分数据

然后:同时包含一个20字节的指针指向其他数据页,可能数据页还是放不下,还需要存储到其他数据页,这些数据页最后会构建一个链表,如图示:

 

六 表空间、段、区和数据页

6.1 数据页

我们知道,数据页存储者数据行,但是数据页只是存储着数据行吗,其实不是的,数据行只是它存储的内容之一,它还有些其他东西,比如文件头,数据页头,最大最小记录,数据行,空闲区域、数据页目录,文件尾部。如图示:


其中文件头占38个字节,数据页头占56字节,最大最小记录占26字节,文件尾部占8个字节,空闲区域和数据页目录大小不确定,刚创建的数据页只有空闲区域,没有数据行。当数据行占据的空闲区域越来越多,则空闲区域越来越少,那么空闲区域写完了,则表示这个页写满了。

 

6.2 数据区(extent)

一个数据区包含多个数据页,由多个连续的数据页组成,每一个区大小为1M,那么数据页大小16K,那么一个区有64个数据页。

6.3 段(segment)

理论上一个表就是一个段,一个段由多个区组成,一般有数据段、索引段、回滚段等,在MySQL数据即索引,数据段即为B+树叶子结点,索引段即为B+树非叶子节点

6.4 表空间(tablespace)

所有的数据都是存储在表空间的,默认情况下所有数据库共享表空间ibdata1, 即所有数据都在表空间里面,如果启用了参数innodb_file_per_table,则每一个表可以对应一个表空间,但是也只是数据、索引存放到都对表空间,回滚、事务等信息还是在共享表空间中。每一个表空间是由不同的段组成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

莫言静好、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值