本文同样参考小孩子写的《MySQL是怎样运行的:从根儿上理解MySQL》
来总结下,一条记录在底层的存储逻辑是怎样的。
InnoDB页简介
这个存储引擎是将表中的数据存储到磁盘上,真正的数据处理是在内存中,innodb将数据划分为若干个页,以页作为磁盘和内存之间交互的基本单位,大小一般为16KB
。
行格式
指定行格式:
CREATE TABLE 表名 (列的信息) ROW_FORMAT=行格式名称
ALTER TABLE 表名 ROW_FORMAT=行格式名称
compact行格式
一条完整的记录可以被分为记录的额外信息
和记录的真实数据
。
一、记录的额外信息
是服务器为了描述这条记录而不得不额外添加的一些信息
,分为:变长字段长度列表、null值列表和记录头信息。
变长字段长度列表
变长字段的数据类型如:varchar(M) 各种text类型、各种blob类型,这种变长字段中存储多少字节是不固定的,所以变长字段的存储空间分为2部分:真正的数据内容+占用的字节数。
- 在compact行格式中,把
所有变长字段的真实数据占用的字节长度都存放在记录的开头部位
,从而形成一个变长字段长度列表,各变长字段数据占用的字节数按照列的顺序逆序存放
。 - 这些字节选取的存储方式:如果该可变字段允许存储的最大字节数W*M超过255且真实存储的字节数超过127字节,则使用2个字节,否则使用1个字节。
- 只存储值为非NULL的列内容占用的长度,值为NULL的列的长度是不储存的。
- 并不是所有记录都有这个变长字段长度列表,比如说表中所有的列都不是变长的数据类型的,这一部分就不需要有。
NULL值列表
表中的某些列可能存储NULL值,如果都放到记录的真实数据中存储会很占地方,所以统一管理起来,存储到null值列表中,处理过程如下:
- 1.首先统计表中允许存储null的列有哪些。
- 2.如果表中没有允许存储null的列,则null值列表也不存在了。否则将每个允许存储null的列对应一个二进制位,二进制位按照列的顺序逆序排列,值为1时表示该列的值为null,值为0时,代表值不为null。
- 3.必须用整数个字节的位表示,如果不是整数个字节,则在字节的高位补0。类推,如果有9个允许为null,则需要用2个字节来表示。
记录头信息
由固定的5个字节组成,即40个二进制位,不同的位代表不同的意思,如表示该记录是否被删除,拥有的记录数等。
- delete_mask 标记该记录是否被删除
- min_rec_mask,B+树的每层非叶子节点中的最小记录都会添加该标记
- n_owned,占4位,当前记录拥有的记录数
- heap_no,占13位,当前记录在记录堆的位置信息
- record_type,占3位,当前记录的类型,0普通记录,1B+树非叶子节点,2最小记录,3最大记录
- next_record,占16位,下一条记录的相对位置
delete_mask
用来标记该记录是否被删除,因为移除记录会把其他记录在磁盘上重新排列,所以只是打上删除标记,这些删除的记录会组成所谓的垃圾链表,在这个链表中记录占用的空间称之为可重用空间,之后如果有新记录插入到表中的话,可能把这些被删除的记录占用的存储空间覆盖掉
。
heap_no
表示当前记录在本页中的位置。
innodb自动给每个页
里加两个记录,称为伪记录
或者虚拟记录
,一个代表最小记录,一个代表最大记录,(对于一条完整的记录来说,比较记录大小就是比较主键的大小)
record_type
next_record
从当前记录的真实数据导下一条记录的真实数据的地址偏移量。下一条记录是指按照主键值有小到大顺序的下一条记录,
规定Infimum即最小记录的下一条记录就是本页中主键值最小的用户记录,而本页中主键值最大的用户记录的下一条记录是Supremum即最大记录。指针指向下一条记录的 记录头信息和真实数据之间的位置,这个位置向左读取是记录头信息,向右读取是真实数据,这样可能会提高高速缓存的命中率(字段和字段长度信息在内存中的距离更近)
innodb对于已经删除的记录,再次插入时还是会重用这部分存储空间。
二、记录的真实数据
MySQL会为每个记录默认的添加一些列(隐藏列)。
innodb表对主键的生成策略:优先使用用户自定义主键,如果没有选取一个Unique键作为主键,否则innodb会为表默认添加一个名为row_id的隐藏列作为主键。
char(M)列的存储格式
对于char类型的列来说,当列采用的是定长字符集时,该列占用的字节数不会被加到变长字段长度列表,如果采用变长字符集时,该列占用的字节数也会被加到变长字段长度列表。
行溢出
对于varchar类型的列最多可以占用65535个字节,减去记录的额外信息,是65532个字节,针对不同的字符集,分别存储的字符则是65532/3 。
在compact和Reduntant行格式中,对于占用存储空间非常大的列,在记录的真实数据只会存储该列的前768个字节,把剩余的数据分散存储在几个其他的页中,然后用20个字节存储指向这些页的地址,从而找到剩余数据所在的页,这些剩余的数据也叫做行溢出
,存储这些页面的叫溢出页
.
Dynamic和Compressed行格式
和compact行格式的区别是把所有的字节都存储到其他页面中,只在记录真实数据处存储其他页面的地址。
原文地址:https://www.cnblogs.com/efan/p/10840397.html