WHCSRL 技术网

Mysql InnoDB存储引擎的数据存储模型(1)

Mysql InnoDB存储引擎的数据存储模型

本次会先从mysql表中的一行数据开始入手分析它的数据结构设计,包括一行如何存储在磁盘中、如何从磁盘中读取、存储的结构的是如何一步步演变设计的,在了解完一行数据的设计之后,再从一行数据的设计层面拔高到一个数据页、一个数据区、一个数据区组以及一个表空间的设计层面,最后拓展下redo log和undo log的数据结构并结合Buffer Pool缓存机制,回放下更新一条数据的整体流程

在这里插入图片描述

在磁盘中如何存放一行数据

往mysql中的表插入一行数据我们是再熟悉不过了,但是对于一行数据是怎样存储在磁盘中可能会比较模糊,简单来说mysql表中一行数据的结构由以下几个部分组成:

在这里插入图片描述

在分析上图几个概念之前,我们先看下一行数据应该是怎样存放在磁盘中的。我们简单点,比如某张表就三个字段,类型为:varchar(10) char char,插入一条数据如: hello a a,那么它应该怎样存放在磁盘呢?在磁盘中存储样子大概就是:hello a a,如果再来一条数据:hi a a,相应在磁盘中的存储大概就为:hello a a hi a a,没错,就像大家看到的一样,mysql的设计者就是这么的抠门,在磁盘中数据就是紧挨着存放的,但是极大的节约了内存空间,存储效果如下所示:

在这里插入图片描述

变长字段长度列表

现在如果要从磁盘读取第一行数据如:hello a a 该怎样读取呢?首先肯定要知道我们读取的那条数据的长度,才能把那条数据在磁盘中给完整读取出来;第一个问题就在于这行数据有一个变长字段的类型为varchar(10),变长字段的长度是可能会变化的,导致一行数据的长度并不是固定的;为了解决这个问题,mysql在设计每行数据结构时引入了可变字段长度列表,对于每行数据,会把varchar类型字段的长度记录到变长字段长度列表中,如下图所示:

在这里插入图片描述

这里变长字段长度列表的大小是用16进制形式存放的;这个时候可能有人要问了,如果有多个字段为varchar类型,那么在变长字段长度列表该如何存放?这里它还有点讲究,就是会按照顺序,以16进制的格式逆序存放到变长字段长度列表中,如下图:

在这里插入图片描述

引入变长字段长度列表后,每行数据中的变长字段长度列表中就都记录了这些信息,比如第一行中的varchar字段的值分别为hello和dba、长度分别为5和3以16进制逆序存放;第二行中的varchar类型字段的值分别为hi和dba、长度分别为2和3以16进制逆序存放,那么这个时候如果要从磁盘中读取数据时不就很方便了吗:

读取一行数据时,扫描到第一个和第三个字段是变长字段类型varchar,就先到变长字段长度列表看下字段的长度,然后根据读取到的字段长度依次读取数据,然后接下来是char、char都是定长的字段类型,直接分别读取一位,这样一条数据不就顺利读到了吗。

null值列表

第一个问题对于可变字段的长度问题,我们就已经通过引入变长字段长度列表、逆序存放它们长度的16进制数据来解决了;另外一种情况,就是一行数据的字段不光会出现变长字段,还有可能存在null值的情况,这些可以为null的字段它们的长度也不是固定的,只要字段长度不是固定的,就会妨碍我们预估要读取的那行数据的长度,这里我们先看一个案例,先创建一张表:

在这里插入图片描述

以上的建表语句中我们可以看到,除了name字段,其他字段都是可以为null的,比如表中有一条数据为:
jack NULL m coding NULL,第二个和最后一个字段的值恰好为null,可以为null的字段和varchar都有一个特征就是你不确定它的长度,为不为null都不一定,这同样会在我们读取一行数据时,影响我们预估一行数据的长度。

为了解决这个问题,mysql类似处理varchar一样,设计了一个null值列表,和变长字段长度列表一样,它的本质也是用来确定哪些字段为null值,这里和变长字段长度列表不同的是,它不是简单用一个数字记录字段的长度,而用一个bit为来标记字段是否为null,1:表示字段为null值,0:表示字段不为null值,毕竟是不是null就两种可能,不需要像varchar一样,拿一个更占内存的数字来表示,那么分析到这里我们就知道上面一行数据 jack NULL m coding NULL 对应的null值列表应该为 [01001],和变长字段长度列表的逆序排列特征一样,null值列表也要逆序存放,这时就为:[10010],但是一般至少也是8个bit位即一个字节的大小才行,所以这边前面补全来就是:[00010010],如下图所示:

在这里插入图片描述

引入null值列表之后,此时如果我们再要去磁盘读取一行数据的话,遇到某个字段可以为null,就先从null值列表中获取该字段对应的bit位,bit位为1字段的值就为null,这个时候就跳过不读取,bit位为0则字段的值不为null,这个时候如果该字段恰好又为varchar字段,再从变长字段长度列表得到字段的长度,完整的读取数据,这样一行数据中不确定的两个因素:varchar字段、null值,就通过我们引入的变长字段列表和null值列表解决了。

文章2

推荐阅读