WHCSRL 技术网

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

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

文章1

数据头

接下来我们再简单了解下一行数据中数据头是什么,简单来说一行数据的数据头就是用来描述该行数据的,数据头由40个bit位组成。

在这40个bit位组成的数据头中,前2位是预留位,暂时没什么含义;第3位为delete_mask表示如果一行数据被删除了,该位就被标记为1,从这里我们知道了一行数据被删除肯定就不是简单从mysql中彻底消失了;min_rec_mask 是在B+树中、每层非叶子节点的最小记录会有该标记(这里牵扯到到索引了,大家先有个印象就行);n_owned 为记录数,这里涉及到一个数据页中是如何组织内部的多行数据、如何方便检索数据的设计,这个我们在后文B+树索引那里再详细研究下;heap_no 顾名思义就是在堆中的位置,这里就是指当前数据行在数据页中的位置;record_type表示该行数据的类型,比如是最大值呢还是最小值、是普通的数据行呢还是B+数中的非叶子节点数据行等数据行类型相关的标记;next_record 表示指向下一条数据的指针,数据行在数据页中是以单向链表的方式存放的;相比于上面这些烧脑的文字,我们还是来看下下面这张图吧:

在这里插入图片描述

数据头了解了之后,对于一行数据在磁盘中的存储我们又更进一步的了解了,现在引入数据头之后,一行数据在磁盘中的样子大概看起来就像下面一样了:

在这里插入图片描述

实际数据

了解完变长字段长度列表、null值列表以及数据头之后,现在完整的一行数据就差实际数据了,其实实际数据它并不是说像上面jack m coding的格式存放的,而是会先解析成字符编码的样式存放,如下图所示:

在这里插入图片描述

这里需要再补充一点的就是,在实际数据中会有几个隐藏字段,分别是:DB_ROW_ID:表示行的唯一标识,一般情况都是主键,就算没主键它也会自动给你生成一个,目的就是唯一标记该行数据;DB_TRX_ID:事务ID,这里主要记录最近一次被哪个事务给修改操作过,新增、修改、删除,都会记录事务的ID,该标记在后续研究MVCC机制时会起到非常大的作用;DB_ROLL_PTR:表示回滚指针,在事务回滚时与undo log有关,这个暂时可以简单了解下。所以当我们了解了几个隐藏字段后,实际存储在磁盘中的一行数据最终看起来就如下图所示:

在这里插入图片描述

【一行数据在数据页中的存储】
数据页的数据存储模型,我们直接先看一张图:

在这里插入图片描述

上图中对于最大记录、最小记录、数据页目录这块的内容也和上文的记录数一样,在分析索引时详细了解下;现在对于一行数据如何存放在数据页中,我们主要关注空闲区以及数据区;当数据页中没有数据时,数据区几乎不占内存,随着一行行数据进入数据页,空闲区的内存逐渐被耗尽,动态效果如下图所示:

在这里插入图片描述

一个数据页的内存大小为16KB,但是我们常常会发现一个字段如varchar就可以指定为varchar(65535),假如65535的空间中都塞满了数据,肯定这一行数据中的一个字段的大小,它占的内存就远远大于一个数据页的16KB大小了,这个时候一个数据页肯定就装不下,这个时候会让多个数据页共同存放这行数据,原本的数据页就先存放一部分数据,然后用20个字节的一个指针指向其他共同存放该字段数据的其他数据页,此时那些共同参与数据存放的数据页被称为溢出页,毕竟一行数据都从一个数据页溢出了,如下图所示:

在这里插入图片描述

【数据页在表空间中的划分和存储】
数据表只是逻辑上的一个概念,在实际的物理存储上,mysql InnoDB存储引擎的设计中,一张表则对应一个表空间,同时一个表空间就映射到磁盘中的一个表空间文件,表空间文件以.ibd为文件后缀,大家可以到mysql的安装目录mysqlrootdata下看下每张数据表是不是都对应着一个.ibd的表空间文件。

而数据页理所应当存放在表空间中,但一个数据页才16KB大小,大量的数据页堆在表空间里当然不太好管理,这里又引入了数据区的概念:一个数据区中可以存放64个数据页即一个数据页大小为1MB大小,如下图所示:

在这里插入图片描述

推荐阅读