首页 > 数据库 >MySQL之B+树分析

MySQL之B+树分析

时间:2024-10-09 13:46:27浏览次数:8  
标签:分析 索引 查找 键值 二叉树 MySQL 数据 节点

概览

索引是一种数据结构,用于帮助我们在大量数据中快速定位到我们想要查找的数据。

索引好比一本好书的目录页,需要查询某个章节直接在目录页查找,然后打开响应页数。

但索引也不是就快,如果章节少,那就直接翻开书找即可很快找到,只有章节非常多时,我们就可以利用索引快速找到。

所以,如果想让索引发挥出其真正的实力,需要在数据量大之时才可放心使用索引,反之就是大材小用。

MySQL 中索引分类

  • B + 树索引
  • Hash 索引
  • 全文索引

以下篇幅会以 InnoDB 存储引擎为例分析 B+ 树索引。

在此之前,看下 B+ 树 的演化:

graph LR A(二叉树) --> B(平衡二叉树) --> C(B 树) --> D(B+ 树)

二叉树

二叉树

如上图中展示,商品表建立了一个二叉树查找的索引。

图中可以看到二叉树的节点,节点中存储了键(key)和数据(data);键对应商品表中的 id,数据对应商品表中的行数据。

二叉树特性:任何节点的左子节点的键值都小于当前节点的键值,右子节点的键值都大于当前节点的键值;顶端的节点为根节点,没有子节点的节点为叶子节点。

若现在要查询 id = 12 的商品信息,通过创建的二叉树索引,查询流程如下:

  1. 将根节点作为当前节点,把 12 与当前节点的键值 10 比较,12 大于 10,接下来把当前节点的右子节点作为当前节点,也就是 13
  2. 把 12 和当前节点的键值 13 比较,发现 12 小于 13,把当前节点的左子节点作为当前节点,也就是 12
  3. 把 12 和当前节点的键值 12 比较,12 等于 12,满足条件,从当前节点取出 data,即 id = 12,name = xm

通过二叉树查找需要 3 次即可找到匹配的数据;若在表中一条一条的查询,需要 6 次才可以找到。

平衡二叉树

image-20241008215309053

二叉树若是以上这样的结构,就变成了链表。

现在要查询 id = 17 的商品信息,需要查找 7 次,也就是相当于全表扫描;导致这样的原因主要是二叉树查找变得不平衡了,即:高度太高了,从而致使查找效率不稳定。

so,为了保证二叉树一直保持平衡,就要用到平衡二叉树呢。
平衡二叉树(AVL 树),在满足二叉查找树特性的基础上,要求每个节点的左右子树的高度差不能超过 1。如下为平衡二叉树与非平衡二叉树的比较图:

image-20241008221250760

平衡二叉树保证了树的构造是保持平衡的,当插入或删除数据导致不满足平衡二叉树不平衡时,平衡二叉树会进行调整树上的节点来保持平衡。

B 树

数据在内存中存放是不可靠的,实际中会将例如商品表中的数据和索引存储在磁盘中;但磁盘相较于内存,读取数据的速度会慢上千百倍,所以应该尽量减少从磁盘中读取数据的次数;还有从磁盘读取数据时,都是按照磁盘块读取的,并不是一条记录一条记录读的;如果能将数据放进磁盘块中,那么一次磁盘读取操作就会读取更多的数据,超找数据的时间就会减低。如果用树这种数据结构作为索引的数据结构,那么每次查找数据就只需要从磁盘中读取一个节点(磁盘块)。而平衡二叉树每个节点只存储一个键值和数据,这样每个磁盘块就只能存一个键值和数据,大量数据存储的情况,就会出现二叉树节点多,高度高,导致查找数据进行的磁盘 IO 次数也随之变多,以至于查找数据的效率极具降低。如下图所示:

image-20241008223436780

为了解决平衡二叉树的这个弊端,我们应该寻找一种单个节点可以存储多个键值和数据的平衡树,而 B 树就满足这种情况。

B 树(Balance Tree)即为平衡树的意思,如下是一个 B 树:

image-20241008230355582

图中的 p 节点为指向子节点的指针。

图中的每个节点称为页,页就是我们上面说的磁盘块,在 MySQL 中数据读取的基本单位都是页。

从上图可以看出,B 树相对于平衡二叉树,每个节点存储了更多的键值(key)和数据(data),并且每个节点拥有更多的子节点,子节点的个数一般称为阶,上述图中的 B 树为 3 阶 B 树,高度也会很低。

基于这个特性,B 树查找数据读取磁盘的次数将会很少,数据的查找效率也会比平衡二叉树高很多。

假如我们要查找 id=28 的用户信息,那么我们在上图 B 树中查找的流程如下:

  1. 先找到根节点也就是页 1,判断 28 在键值 17 和 35 之间,那么我们根据页 1 中的指针 p2 找到页 3
  2. 将 28 和页 3 中的键值相比较,28 在 26 和 30 之间,我们根据页 3 中的指针 p2 找到页 8
  3. 将 28 和页 8 中的键值相比较,发现有匹配的键值 28,键值 28 对应的用户信息为(28,bv)

B+ 树

image-20241009132706899

B+ 树与 B 树区别:

  • B+ 树非叶子节点上是不存储数据的,仅存储键值,而 B 树节点中不仅存储键值,也会存储数据。之所以这么做是因为在数据库中页的大小是固定的,InnoDB 中页的默认大小是 16KB。
    如果不存储数据,那么就会存储更多的键值,相应的树的阶数(节点的子节点树)就会更大,树就会更矮更胖,如此一来我们查找数据进行磁盘的 IO 次数又会再次减少,数据查询的效率也会更快。
    另外,B+ 树的阶数是等于键值的数量的,如果我们的 B+ 树一个节点可以存储 1000 个键值,那么 3 层 B+ 树可以存储 1000×1000×1000=10 亿个数据。
    一般根节点是常驻内存的,所以一般我们查找 10 亿数据,只需要 2 次磁盘 IO。

  • 因为 B+ 树索引的所有数据均存储在叶子节点,而且数据是按照顺序排列的。
    那么 B+ 树使得范围查找,排序查找,分组查找以及去重查找变得异常简单。而 B 树因为数据分散在各个节点,要实现这一点是很不容易的。

B+ 树中各个页之间是通过双向链表连接的,叶子节点中的数据是通过单向链表连接的。

其实上面的 B 树我们也可以对各个节点加上链表。这些不是它们之前的区别,是因为在 MySQL 的 InnoDB 存储引擎中,索引就是这样存储的。也就是说上图中的 B+ 树索引就是 InnoDB 中 B+ 树索引真正的实现方式,准确的说应该是聚集索引。

通过上图可以看到,在 InnoDB 中,我们通过数据页之间通过双向链表连接以及叶子节点中数据之间通过单向链表连接的方式可以找到表中所有的数据。

MyISAM 中的 B+ 树索引实现与 InnoDB 中的略有不同。在 MyISAM 中,B+ 树索引的叶子节点并不存储数据,而是存储数据的文件地址。

跳表

聚集索引&非聚集索引

在 MySQL 中,B+ 树索引按照存储方式的不同分为聚集索引和非聚集索引。

只说 InnoDB 中的聚集索引和非聚集索引:

  1. 聚集索引(聚簇索引):以 InnoDB 作为存储引擎的表,表中的数据都会有一个主键,即使你不创建主键,系统也会帮你创建一个隐式的主键。
    这是因为 InnoDB 是把数据存放在 B+ 树中的,而 B+ 树的键值就是主键,在 B+ 树的叶子节点中,存储了表中所有的数据。
    这种以主键作为 B+ 树索引的键值而构建的 B+ 树索引,我们称之为聚集索引。

  2. 非聚集索引(非聚簇索引):以主键以外的列值作为键值构建的 B+ 树索引,我们称之为非聚集索引。非聚集索引与聚集索引的区别在于非聚集索引的叶子节点不存储表中的数据,而是存储该列对应的主键,想要查找数据我们还需要根据主键再去聚集索引中进行查找,这个再根据聚集索引查找数据的过程,称为回表。

聚集索引查找数据

image-20241009132706899

以上是一个聚集索引。

假设查询 id >= 18 并且 id < 40 的用户数据。对应的 sql 语句为:

select * from user where id >= 18 and id < 40

id 是主键,查询过程如下:

  1. 根节点一般情况下是在内存中,即:页 1 已存在于内存中,此时不需要到磁盘中读取数据,直接在内存中读取;
    从内存汇总读取到页 1,要查找这个 id >= 18 and id < 40 的范围值,首先要找到 id = 18的键值;
    从页 1 中可以找到键值 18,此时需要根据指针 p2,定位到页 3;
  2. 从页 3 中查找数据,就需要用 p2 指针去磁盘中进行读取页 3;
    从磁盘中读取页 3 后将 页 3 放入内存中,然后进行查找,看可以找到键值 18,之后拿到页 3 中的指针 p1,定位到页 8;
  3. 同样的页 8 不存在内存中,需要从磁盘中将页 8 读取进内存中;
    将页 8 读取到内存中后,页中的数据是链表进行链接的,而且键值是按照顺序存放,可以根据二分查找法定位到键值 18;
    此时已经找到数据页,同时也找到了满足 id = 18 的数据,即:键值 18 对应的数据;
    因是范围查找,而且此时所有的数据又都存在叶子节点,并且是有序排列的,因此,可以对页 8 中的键值依次遍历查找并匹配满足条件的数据;
    一直遍历查找,找到键值为 22 的数据,之后页 8 中就没有数据了,此时需要用页 8 中的 p 指针去读取页 9 中的数据;
  4. 而页 9 不在内存中,就又会加载页 9 到内存中,并通过和页 8 中一样的方式进行数据的查找(遍历、p 指针),知道将页 12 加载到内存中,发现 41 大于 40,这时就不满足条件了,结束查找。
  5. 最终我们找到满足条件的所有数据,总共 12 条记录:
    (18,kl), (19,kl), (22,hj), (24,io), (25,vg) , (29,jk), (31,jk) , (33,rt) , (34,ty) , (35,yu) , (37,rt) , (39,rt)

查找详情流程图:
image-20241009132820037

非聚集索引查找数据

非聚簇索引会根据二级索引找到主键,之后,拿着主键回表查询(和聚簇索引流程一致);

减少回表查询

索引覆盖

一个查询可以完全通过索引来执行,无需访问实际的数据行。即:一个索引包含了需要查询的所有字段 -> 联合索引

索引下推可以避免回表

尽可能把查询条件推到索引层面进行过滤,减少从磁盘读取的数据量。但是 ta 依赖于存储引擎层面

标签:分析,索引,查找,键值,二叉树,MySQL,数据,节点
From: https://www.cnblogs.com/zhzcc/p/18454042

相关文章

  • 我店生活模式功能分析
    一、平台概述“我店”由上海我店科技网络有限公司创立于2021年8月,作为一个本地生活服务平台,它致力于响应国家的环保政策,并运用绿色积分来促进经济活动,帮助实体店铺吸引客流。面对实体商业的挑战,“我店”平台凭借其独特的商业模式,为商户与顾客提供了新的合作与发展机遇。二、核......
  • 基于Java+SpringBoot+Mysql在线年度考核考勤管理系统功能设计与实现九
    一、前言介绍:1.1项目摘要随着计算机和网络技术的迅猛发展,学校教学和管理的信息化发展也得到了长足的进步,学校是否具有一流的信息管理、教育教学的平台已经是衡量一个学校信息化建设的重要标志之一。本文首先介绍了在线考试系统的开发背景,开发工具,结构化开发的具体步骤,然......
  • 基于Java+SpringBoot+Mysql在线年度考核考勤管理系统功能设计与实现十
    一、前言介绍:1.1项目摘要随着计算机和网络技术的迅猛发展,学校教学和管理的信息化发展也得到了长足的进步,学校是否具有一流的信息管理、教育教学的平台已经是衡量一个学校信息化建设的重要标志之一。本文首先介绍了在线考试系统的开发背景,开发工具,结构化开发的具体步骤,然......
  • 算法分析
    算法导论这个文档是学习“算法设计与分析”课程时做的笔记,文档中包含的内容包括课堂上的一些比较重要的知识、例题以及课后作业的题解。主要的参考资料是Introductiontoalgorithms-3rd(ThomasH.)(对应的中文版《算法导论第三版》),除了这本书,还有的参考资料就是Algorithmsdesi......
  • GIS、向量、文字检索... 火山引擎 ByteHouse 集成全场景分析能力
    企业业务场景增多、规模扩大,对于底层数据架构来说,可能也会愈加复杂。 比如,某企业因自身业务发展,需要引入向量检索能力,但前期选型的技术架构并不能直接支持,只能重新引入向量数据库。这意味着,研发团队要维护多个组件,让底层架构非常复杂,不仅带来数据冗余,也给数据运维带来压力,造成......
  • Axure大屏可视化模板在多领域实践应用案例分析
    Axure大屏可视化模板,凭借其强大的功能性和灵活性,在众多领域中发挥着举足轻重的作用。本文将详细探讨Axure大屏可视化模板在农业、园区管理、智慧城市、企业数据可视化和医疗领域的应用案例,展示其如何助力各行业实现智能化管理和决策优化。一、农业领域:智慧农业的得力助手智慧......
  • 基于springboot的Hive的网络电视剧收视率分析系统
    本网络电视剧收视率分析系统依托Java与SpringBoot技术,并结合Hive数据仓库,致力于为电视剧行业提供精准、全面的收视率分析服务。在系统设计上,充分考虑数据的海量性和复杂性。Java语言确保了系统各个模块的稳定运行和高效执行。SpringBoot框架则为系统提供了便捷......
  • 高带宽示波器在信号测试分析中的优势和主要应用场景
    最近,普源精电推出了一款13GHz带宽的示波器DS81304,。有些小伙伴会好奇,为什么普源示波器的带宽会从5GHz跳到13GHz,为什么不是到10GHz或者15GHz呢?13GHz的示波器又能干些什么呢?下面讲为大家介绍,为什么DS81304设计为13GHz带宽,以及DS81304相比5GHz带宽的DS70504又能有什么特点。为......
  • MySQL的索引
    MySQL索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可提高数据库中特定数据的查询效率。本节将介绍索引的含义、分类和设计原则。7.1.1索引的含义和特点索引是一个单独的、存储在磁盘上的数据库结构,包含了对数据表里所有记录的引用指针。使用索引可以快速找出在......
  • MySQL 官宣:支持读写分离了!!
    我们一直在等待的MySQL读/写分离功能现在终于可以使用了!在规模上,我们在副本之间分配读取,但这必须在应用程序中以某种方式进行管理:指向在某个地方写入并在其他地方读取。在MySQL8.2中,MySQLRouter现在能够识别读取和写入,并将它们路由到主实例(如果是InnoDB集群),或者路由到......