抛开数据结构,InnoDB中B+树究竟存的是什么

提出问题

  • InnoDB中B+树各个节点存储的内容是什么?
  • InnoDB中索引的种类有哪些?它们节点存储的内容各自有什么区别?

数据页

InnoDB中页是内存和磁盘交互的基本单位, 默认是16KB。其中存储用户记录的页被称为数据页,也被称为索引页。

数据页的组成

image-20220316163300917

其中我们重点关注的就是 User RecordPage Directory 两个组成部分。

  • User Record 用于存储真实的用户数据。
  • Page Directory 可以理解为对 UserRecord 中的数据建立的目录。

下面我们来详细对这两个结构进行分析。

User Record

User Record 是数据页中真实存储用户数据的组成部分。

User Record的特点
  • 数据与数据之间是单向链表,从上一个数据可以找到下一个数据。
  • 数据按照主键的顺序进行排序。
  • InnoDB对User Record中的数据进行分组,最多一个分组里面存储8条数据。

这里我们思考下,为什么需要对数据进行分组?

我们想一下场景,当我们根据主键查询一条记录时,如果只有单向链表的特点,我们需要从开始到结尾去遍历整个页面然后才能获取到我们所需要记录,时间复杂度也就是 O(n)。此时我们引入分组的概念,并记录每个分组中主键最大记录的位于当前页的偏移量,采用二分法的形式,每次获取到一个分组中最大的记录的主键,然后与查询条件主键进行比较,从而快速的定位到所在的分组后,再按照单向链表找到指定的主键对应的记录。这样查询效率迅速提升,时间复杂度就是 O(logm)这里的m也就是分组的个数。

这里也就引出了Page Directory的作用。

Page Directory

Page Directory 可以理解为对 UserRecord 中的数据建立的目录。对应着 User Record中记录的分组信息。Page Directory中存储着多个 slot,也就是槽,每一个槽也就记录着分组中主键最大记录位于当前页的偏移量,能够快速定位到指定的记录。

多个数据页之间的关系

现在我们分析完了单个数据页的结构,并对InnoDB针对单个数据页进行查询优化做了简单的介绍,那么当存储的数据过多而有多个数据页时InnoDB又是如何处理的呢?

这里我们对数据页中 File Header 简单说下, File Header中记录了当前数据页的上一个页的地址和下一个页的地址,简单来说,页与页之间是一个双向链表。

根据双向链表,当我们在多个页之间根据主键查询某条记录时,按照顺序去在每个页面里面去查找,效率比较低。 此时考虑多个页面中是否存在类似于单个页面中分组的概念,能够快速定位到记录对应的页呢?

此时我们引出了存储目录信息的数据页,而不是存储真实用户数据的的数据页。

存储目录信息的数据页

这里的目录信息就是包含其他数据页的页码信息(根据页码信息方便定位到对应的数据页)以及对应数据页中最小主键的值的记录。

在InnoDB中,不管是存储目录的数据页其实还是存储真实数据的数据页是一个概念,它们拥有完全一致的页结构,不用之处在于 UserRecord存储的真实内容不同,在User Record中的记录有一个字段专门记录当前记录存储的是页面信息还是真实用户数据。

这里我们依据存储目录信息的数据页来模拟根据主键进行查询。

如图所示:

image-20220317110829102

  • 在存储目录信息的数据页中根据 Page Directory中的信息,利用二分法快速找到主键所在的数据页信息。
  • 定位到数据页之后,也就很快在单数据页中定位到指定的记录。

值得我们注意的是,此时数据量并不是很大,只是用到一个存储目录信息的数据页,但是当数据量达到百万、千万或者亿级别以上的时候,此时依赖同层(与存储真实数据的数据页直接相连的存储目录信息的数据页)的存储目录信息的数据页可能也会非常多,那么如何进一步提升性能呢?

此时,我们想到我们可以保存存储真实数据的数据页信息,为什么不进一步保存存储目录信息的数据页信息页呢?从而就有了以下的数据结构:

image-20220317112648483

注:其中省略了部分信息

  • 页3用于记录页4、页5、页6的信息,它们存储的都是目录信息。
  • 根据最上级的目录信息的数据页很快定位到下一级的存储目录信息的数据页,从而定位到真实的数据。

从上图结构可以看出InnoDB中数据页的构建像是一棵树,这就是InnoDB所对应的B+树。在InnoDB中根据索引类型的不同,B+树中存储的内容也有点不同。

索引

InnoDB中所以大概可以分为如下几种:

  • 聚簇索引
  • 二级索引
  • 唯一索引
  • 联合索引

接下里分别介绍下上述索引的特点以及对应的数据页存储的内容。

聚簇索引

聚簇索引可以简单理解为针对主键建立的索引。

特点
  • InnoDB根据主键自动创建的索引。
  • B+树中非叶子节点存储的是对应数据页中最小主键信息,以及主键对应的页码信息。
  • B+树中叶子结点存储的是真实的数据。

二级索引

二级索引可以简单理解为根据索引构建的B+树只能查询到对应的主键信息,后续还需要根据主键信息通过聚簇索引获取到真实的数据,这也叫 回表 操作,也就是为什么叫做二级索引的原因。

特点

  • InnoDB根据用户指定的字段创建的索引。
  • B+树中同层级节点按照指定的索引字段进行排序。
  • B+树中非叶子节点存储的对应数据页中最小的索引字段的的信息、对应的主键信息、对应的页码信息。
  • B+树中叶子节点存储的就是索引字段信息、对应的主键信息。

其中存储目录信息的数据页,也就是非叶子节点为什么还需要存储主键信息呢?

是因为方便处理索引字段对应的值相同时引发的问题,在索引字段值相同时,他们无法进行有效的排序,简单来说就是需要确保存储的目录信息的数据页的User Record中每条记录的唯一性,当索引字段对应的值相同时,再按照主键的值进行排序。

唯一索引

唯一索引可以理解为特殊的二级索引,它们建立的索引结构与二级索引一致,唯一不同的是唯一索引对应的B+树是InnoDB自行创建,而非用户创建。

联合索引

联合索引也可以理解为特殊的二级索引,不同之处在于在联合索引中,先根据联合索引中前面的索引字段的值进行排序,遇到相同的值的话,再按照联合索引中下一个索引字段的值进行排序,当然,最后要是索引字段全部相同再以主键对应的值进行排序。

看到此处,开篇提出的问题相信已经得到解答了。

番外话

一般情况下,B+树的深度为4级就够了,为什么呢?

我们假设一下,对于16KB的数据页,可以存储真实数据为100条,而存储目录信息的数据为1000条。那么对于深度为4的B+树,可以存储多少条数据呢?

1000 * 1000 * 1000 * 100 = 100 000 000 000条记录,一般情况下,真实的数据不会都不会超过这么多,所以B+树深度一般都不会超过4。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值