【ⓂMySQL】为什么选择B+树作为数据库索引结构?谈谈你的理解

我们需要明白:

最常用的数据尽可能放在更高层、更小的存储器中,只有在当前层找不到,才向更低层、更大的存储器中寻找。这也就解释了,当处理大规模数据的时候(指无法将数据一次性存入内存),算法的实际运行时间,往往取决于数据在不同存储级别之间的IO次数。因此,要想提升速度,关键在于减少IO。

磁盘读取数据是以数据块(block)(或者:页,page)为基本单位的,位于同一数据块中的所有数据都能被一次性全部读取出来。

一个著名的局部性原理:当一个数据被用到时,其附近的数据也通常会马上被使用,程序运行期间所需要的数据通常比较集中

数据库索引因数据量较大,一般都是存储于外存中,而程序是在内存中执行的,这样就需要进行频繁的I/O操作,那么,为了减少I/O次数,该怎么做呢?

索引设计需要考虑的第一个核心因素:保证每页包含尽可能多的关键信息,来减少磁盘I/O

一般来说,可提升查找速度的数据结构有以下两种:

  • 哈希。比如HashMap,其查询、插入、删除的平均时间复杂度均是O(1);
  • 树。比如二叉查找树,其查询、插入、删除的平均时间复杂度均是O(log(n))。

可以看到,论时间复杂度,不管是读请求,还是写请求,哈希的性能会更好,可为什么DB却选择使用B+树呢?

索引设计需要考虑的第二个核心因素:结合DB各种搜索场景,选取更合适的数据存储结构

哈希表

假设采用HashMap存储,如果查询sql都是单行查询

select * from user where name='zhangsan';

那么,采用哈希确实很快,但是,如果过滤条件是范围(<、>),排序(order by)等查询场景呢?其时间复杂度将退化为O(n)。假设我们采用的是“m叉查找树”,由于其本身是排好序的,其时间复杂度仍将是O(log(n)),即仍能保证其高效率。

哈希表:指定数据的定位较快,范围查询较慢

平衡二叉树(AVL树)

平衡二叉树的,可以认为它是升级版的二叉树,它有两个特征:

  • 数据是有序排列的
  • 任何节点的儿子子树高度差的绝对值不会超过1
  • 采用中序遍历可获得所有节点

从图中可以看出,每个节点有且仅能存储一个记录,如果数据量大的话,树的高度将会很高,故而,当查询数据时,会产生很多次磁盘I/O。

相比哈希表而言,平衡二叉树支持范围查询,解决了哈希表的痛点

B树(平衡多路查找树)

B树的结构有以下特点:

  • 叶子节点和非叶子节点都存储数据(此特点会导致非叶子节点不能存储大量的索引
  • 采用中序遍历亦可获得所有节点

从图中可以看出,每一个节点可以有多个子节点,且每一个节点(包括非叶子节点)均存储数据,采用中序遍历便可查找到所有数据。但是,数据库磁盘交互是按页为单位(MySQL默认为16K)的,如果数据量过多时,每个节点存储的键值会较少,进而树的高度比较高,导致磁盘I/O比较多。同时,在实际项目中,范围查询的SQL比较频繁,倘若采用B树作为索引结构,需要中序遍历很多节点,来收集符合筛选条件的数据集。因此,此结构某种程度来看,不是太合适。

B+树

B+树有以下特点:

  • 非叶子节点仅保存索引和指针(不再存储数据),仅叶子节点存储数据信息(保证节点可以存储更多索引,进而减少树的高度
  • 叶子节点间采用了链表,这样,范围查询时,只要确定范围的左右边界坐标,遍历叶子节点链表,便可获取所有符合条件节点集合

从其特点可得知,它兼具了“降低树高度,减少磁盘I/O”、“提升范围查询性能”两个因素。

举一个例子来说明B+树怎么控制树的高度的。

我们假设一页大小是16KB,每个索引(主键)是bigint类型,即8B,指针为6B。那么每页能存储大约1000个索引(16KB/(8B+6B) \approx1000)。

那么,一颗3层的B+树能够存储多少索引呢?如下图:
大约能够存储10亿个索引。通常 B+ 树的高度在2-4层,由于 MySql 在运行时,根节点是常驻内存的,因此每次查找只需要大约2-3次IO。

结合索引的底层原理,我们在实际项目中构建索引时,需要注意以下几点:

  • 主键不能太大,否则,每个节点可容纳的节点会较少
  • 主键最好是自增的,否则,每次插入都会调整B+树,从而导致页分裂,影响性能

 

 

posted @   残城碎梦  阅读(49)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
历史上的今天:
2022-03-19 Junit配合Spring进行单元测试
2022-03-19 了解Spring的框架和包结构
点击右上角即可分享
微信分享提示