b+树
带着问题,读文章
我们都知道mysql的innodb是使用数据是B+树,但是我搜了很多博客,却没有资历能讲清除b+树在mysql中到底是如何存储的?或者说 innodb是怎么用表空间(tablespace),段(segment),区(extent),叶(Page),行(row)来实现B+树的。下面是物理存储的关系:
从表空间是innodb 逻辑引擎中最高结构,所有数据都存储在表空间中。(所以这个和b+树关系不大)这里需要的同学可以了解一下 自行了解一下 共享表空间。
行(row)
首先从最基本的来讲,我们存储的数据最基础的存储单位都是行,在物理存储上mysql也是以行来作为最基本的存储单位。行的记录格式有许多格式。innodb中行记录格式 有compact 和 redundant两种。这里只详解一种compact。
compact行记录格式
目前在mysql 5.0以后引入了compact行记录格式,也是现在5.5之后的默认行记录格式,他的记录格式如下:
-
变长字段长度列表
如果 列长度小于255字节 用1字节表示 ,若大于 255字节,用2字节表示。(因为varchar 最大长度为2^16次方 65535)
注意的是:这个是一个列表,每一个值 是每一列的数值长度。 -
null标志位
1个字节,有该行的某列是否null值。如果有null值,则该列所在的位将由0变为1。 -
记录头信息:固定占5字节(40位)
delete flag: 1位 该行是否已被删除。
heapno:13位 索引堆中 该记录的排序记录
next_record:16位 页中下一条记录的相对位置
record_type: 3位 000表示普通 001表示B+树叶子节点指针,010 infimum 011 Supremum 1xxx 表示保留
总结:这里我们已经看到在行记录中,就已经有关于b+树的信息:
record_type: 表示是否是B+树的叶子节点
delete flag:删除位 (猜测:用来进行预删除,因为b+树的删除需要的资源挺多)
以及 和b+树排序相关的信息。
额外知识
mysql 一行数据最大长度不能超过65535 。
猜测:这个是由于在redundant行格式下,(变长字段长度列表)在redundant中是长度偏移列表。两个字节累计是2^16次方 65535.
验证:
这里要用 latin1 的字符集
行溢出数据 nnodb 存储引擎页的大小为16kb,既16384字节,怎么存放 65532字节的字符的呢?
innodb 存储引擎页的大小为16kb,既16384字节,怎么存放 65532字节的字符的呢?
因此:一般情况下,innodb存储引擎的数据都是存放在 页类型为b-tree node中的,但是当发生了行溢出时,
数据就会存放在 uncompress blob页中.如存放一个 65532的数据 只会把768字节的前缀数据存在引擎页中,超过的就存在 blob page中了
对于text 和blob数据诶下。也不是都全放在blob页中,也是只有前768字节放在引擎页中。
页
页中分为7个部分
File Header(文件头)。
Page Header(页头)。
Infimun+Supremum Records。(最小和最小记录值)
User Records(用户记录,即行记录)。
Free Space(空闲空间)。
Page Directory(页目录)。
File Trailer(文件结尾信息)。
由于我们主要是学习b+树相关知识。所以我们只看下面这些
File header
名称 | 占用空间大小 | 占用空间大小 |
---|---|---|
FIL_PAGE_SPACE_OR_CHKSUM | 4字节 | 页的校验和(checksum值) |
FIL_PAGE_OFFSET | 4字节 | 页号 |
FIL_PAGE_PREV | 4字节 | 上一个页的页号 |
FIL_PAGE_NEXT | 4字节 | 下一个页的页号 |
FIL_PAGE_LSN | 8字节 | 页面被最后修改时对应的日志序列位置(英文名是:Log Sequence Number) |
FIL_PAGE_TYPE | 2字节 | 该页的类型 |
FIL_PAGE_FILE_FLUSH_LSN | 8字节 | 仅在系统表空间的一个页中定义,代表文件至少被刷新到了对应的LSN值 |
FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID | 4字节 | 页属于哪个表空间 |
FIL_PAGE_OFFSET | 4字节 | 页号 |
FIL_PAGE_PREV | 4字节 | 上一个页的页号 |
FIL_PAGE_NEXT | 4字节 | 下一个页的页号 |
FIL_PAGE_TYPE 解释
十六进制 | 描述 |
---|---|
0x0002 | Undo日志页 |
0x0003 | 索引节点页 |
0x000A | BLOB页 |
0x45BF | 索引页,也就是我们所说的数据页 |
可以看到 在 file header中 ,有规定这一页是否为 索引页或者数据页,并且也指定了前后页号,代表着在页的层次上,可以理解为b+树的节点,而行数据为b+树节点中的元素
Infimum + Supremum
这部分存储的是固定的两条记录,分别为数据页中的「最小记录」和「最大记录」,如图所示:
这里可以看出 在b+树的叶子节点中查找数据可以配合着 行记录中的next_record来查询数据。
User Records
这里就是行记录在页中的位置,
Free Space
空闲空间,数据页中尚未使用的部分。被删除后的数据也会被放置到这个空间
page directory
简单理解就是讲这个页也分成小块,他存储每个小块某个数据的地址,有点像页(page)的目录
Page Header
这个基本是 和事务相关,以及标注了b+树的层级以及相关信息
名称 | 占用空间大小 | 占用空间大小 |
---|---|---|
PAGE_MAX_TRX_ID | 8字节 | 修改当前页的最大事务ID,该值仅在二级索引中定义 |
PAGE_LEVEL | 2字节 | 当前页在B+树中所处的层级 |
PAGE_BTR_SEG_LEAF | 10字节 | B+树叶子段的头部信息,仅在B+树的Root页定义 |
PAGE_BTR_SEG_TOP | 10字节 | B+树非叶子段的头部信息,仅在B+树的Root页定义 |
参考文件
掘金小册《MySQL 是怎样运行的:从根儿上理解 MySQL》
《MySQL技术内幕:InnoDB存储引擎(第2版)》
https://zhuanlan.zhihu.com/p/149318688