MySQL数据库——索引结构之B+树

本文先介绍数据结构中树的演化过程,之后介绍为什么MySQL数据库选择了B+树作为索引结构。

在这里插入图片描述

文章目录

      • 树的演化
      • 为什么其他树结构不行?
        • 为什么不使用二叉查找树(BST)?
        • 为什么不使用平衡二叉树(AVL树)?
        • 为什么不使用B树?
      • 为什么选择 B+ 树
        • 1. B+ 树节点结构
        • 2. 优点
        • 举例
      • Q&A
        • Hash比B+树更快,为什么Mysql用B+树来存储索引呢?
        • 增加树的路数可以降低树的高度,那么无限增加树的路数是不是可以有最优的查找效率?

树的演化

    • 非线性结构,每个节点有唯一的一个父结点和多个子结点(子树),为一对多的关系。
  1. 二叉树

    • 每个结点最多有两颗子树,并且子树有左右之分,不能颠倒。
  2. 满二叉树

    • 每一层的结点个数都达到了当层能达到的最大结点数。
  3. 完全二叉树

    • 除了最下面一层之外,其余层的结点个数都达到了当层能达到的最大结点数,且最下面一层只从左至右连续存在若干结点,右边的结点全部不存在。
  4. 二叉查找树 (BST)

    • 又称为二叉排序树、二叉搜索树。
    • 定义:
      1. 要么二叉査找树是一棵空树。
      2. 要么二叉查找树由根结点、左子树、右子树组成,其中左子树和右子树都是二叉查找树,其中:
        • 左子树的所有结点值小于或等于根节点值
        • 右子树的所有结点值大于根节点值。
  5. 平衡二叉树 (AVL 树)

    • 特殊的二叉查找树,左右子树都是平衡二叉树,且左右子树高度之差不超过 1。
  6. B 树

    • 又名平衡多路查找树。每个节点包含多个数据及指针域,查找路径有多个分支。B-树就是 B 树(别讲什么B减树,‘-’是分隔符)。
  7. B+ 树
    在 B 树基础上发展而来的平衡多路查找树,非叶子节点只存储键值和指针,所有数据存储在叶子节点,并通过链表连接。
    优化主要体现在以下几个方面:

    1. 非叶子节点不存储数据,更适合磁盘存储和 I/O 优化
      • B 树:所有节点都存储键值和数据。
      • B+ 树:非叶子节点只存储键值和指针,不存储实际数据,使得内部非叶子节点更小,单个磁盘块可容纳更多键值,减少树的高度和磁盘 I/O 次数,降低树的高度。
    2. 叶子节点存储所有数据,更便于顺序遍历,查找效率稳定
      • B 树:数据分散在各个节点,遍历需要中序遍历整棵树。 查询可能在任何节点结束,查询效率不稳定。
      • B+ 树:所有数据存储在叶子节点,并通过链表连接,范围查询、排序查询更高效,可以快速顺序遍历数据,无需回溯,所有查询最终都在叶子节点结束,查找效率稳定。

为什么其他树结构不行?

磁盘读写的特性

  1. 数据库的索引及数据存储在磁盘中,而不是内存中,磁盘 I/O 的速度远慢于内存。
  2. 从磁盘读取数据时,按照磁盘块(页)读取,每次读取的最小单位是一个磁盘块。
  3. 若能将更多数据放入一个磁盘块中,一次读取操作可以获取更多数据,从而减少 I/O 次数,提高查询效率
为什么不使用二叉查找树(BST)?
  • 可能出现链表形态:二叉查找树在数据不平衡时可能退化成一条链表,类似于全表扫描,查找时无法发挥二叉排序树的优势。
  • 高度过高:树的高度过高时,查找效率变得不稳定,查询需要遍历较多的节点,导致性能下降。
为什么不使用平衡二叉树(AVL树)?

平衡二叉树通过自平衡解决了BST高度过高,查找效率不稳定的问题。但是:

  • 节点存储限制:平衡二叉树每个节点只能存储一个键值和数据,对于海量数据,节点数量会非常多,树的高度依然可能较高。
  • 效率降低:对于大量数据的存储和查找效率依然不理想,因为节点存储量有限,高度无法有效缩减。
为什么不使用B树?

B树每个节点有更多子节点,减少了树的高度,从而提高了IO性能。解决了平衡二叉树只能存储一个键值和数据的问题。但是:

  • 遍历效率低:尽管B树提高了IO性能,但在查找数据时,仍然需要遍历整个树,导致遍历效率低,不同的点查询效率不一样,即查询效率不稳定。

为什么选择 B+ 树

在这里插入图片描述

  • 二叉查找树:可能退化为链表,查找效率不稳定。
  • 平衡二叉树:虽然能保证平衡,但对于海量数据,节点数仍多,高度过高。
  • B树:提高了IO性能,解决了平衡二叉树的问题,但遍历效率不足,特别是对于大范围查询。

引入B+树:为了进一步提高遍历效率,B+树在B树的基础上做了优化:

1. B+ 树节点结构
  • 非叶子节点仅存储键值,不存储数据,节点更紧凑。
  • 数据只存储在叶子节点,叶子节点通过双向链表串联形成线性表。查询时只需要扫描叶子节点,从而大幅提高了范围查询和排序查询的效率。
  • 数据库页的大小固定(如 InnoDB 默认 16KB),更高阶数的树更矮更胖,减少了磁盘 I/O 次数。
2. 优点
  1. 磁盘读写代价更低

    • 内部节点不存储数据,节点更小,单个磁盘块可容纳更多键值。
    • 减少树的高度,相同数据量下 I/O 次数更少。
  2. 查询效率更加稳定

    • 查询路径固定,从根节点到叶子节点的路径长度一致,每次查询效率相同。
  3. 更便于遍历

    • 数据全部存储在叶子节点,顺序遍历时只需扫描叶子节点即可。
    • 非叶子节点均为索引,便于范围查询和排序。
  4. 更适合范围查询

    • 叶子节点通过链表连接,直接支持高效的范围查询和排序操作。
    • 在数据库中,基于范围的查询非常频繁,而 B 树不支持或效率较低。

举例

磁盘页大小:默认是 16 KB,也就是16,384 字节(1 KB = 1024 字节)。
假设条件:
2. 每个键值的大小:假设每个键值的大小是 16 字节。
3. 每个节点存储的键值数量:每个磁盘页可以存储 1024 个键值。

  • 如果一个节点可以存储 1000 个键值时(没有超过1024 个键值),3 层的 B+ 树可以存储约 10 亿条数据。
  • 根节点常驻内存,那么查找 10 亿条数据时只需 2 次磁盘 I/O。

Q&A

Hash比B+树更快,为什么Mysql用B+树来存储索引呢?

首先在功能上:

  • B+树可以进行BETWEEN范围查询,Hash索引不能。
  • B+树支持order by排序,Hash索引不支持。
  • B+树使用like 进行模糊查询的时候,like后面(比如%开头)的话可以起到优化的作用,Hash索引根本无法进行模糊查询。
  • B+树支持 InnoDBMyISAMMemory,Hash索引仅支持Memory(默认情况)
  • B+树支持联合索引的最左侧原则,Hash索引不支持。
  • Hash索引在等值查询上比B+树效率更高。

从设计上来看:

  • 从内存角度上说,数据库中的索引一般时在磁盘上,数据量大的情况可能无法一次性装入内存,B+树的设计可以允许数据分批加载
  • 从业务场景上说,等值查询那确实是hash更快,但是数据库中经常会进行排序和范围查询,B+树叶子节点通过双向链表串联形成线性表,它的查询效率比hash就快很多了,hash还需要解决冲突。
增加树的路数可以降低树的高度,那么无限增加树的路数是不是可以有最优的查找效率?

答:这样会形成一个有序数组,文件系统和数据库的索引都是存在硬盘上的,并且如果数据量大的话,不一定能一次性加载到内存中。有序数组没法一次性加载进内存,这时候B+树的多路存储威力就出来了,可以每次加载B+树的一个结点,然后一步步往下找。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/65610.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大模型—Ollama 结构化输出

Ollama 结构化输出 Ollama现在支持结构化输出,使得可以按照由JSON模式定义的特定格式来约束模型的输出。Ollama的Python和JavaScript库已经更新,以支持结构化输出。 结构化输出的用例包括: 从文档中解析数据从图像中提取数据结构化所有语言模型响应比JSON模式更可靠和一致开…

欧拉计划 Project Euler 35 题解

欧拉计划 Problem 35 题解 题干思路code暴力筛法rotate函数使用语法示例代码 题干 思路 一个很自然的思路就是暴力找&#xff0c;遍历一百万之内的所有数&#xff0c;也可以先把一百万以内所有的素数筛出来然后从中取选。这里我使用的是暴力算法。 code 暴力 #include <…

pytorch基础之注解的使用--003

Title 1.学习目标2.定义3.使用步骤4.结果 1.学习目标 针对源码中出现一些注解的问题&#xff0c;这里专门写一篇文章进行讲解。包括如何自定义注解&#xff0c;以及注意事项&#xff0c;相信JAVA中很多朋友业写过&#xff0c;但是今天写的是Python哦。。。 2.定义 在 Python…

C#编写的金鱼趣味小应用 - 开源研究系列文章

今天逛网&#xff0c;在GitHub中文网上发现一个源码&#xff0c;里面有这个金鱼小应用&#xff0c;于是就下载下来&#xff0c;根据自己的C#架构模板进行了更改&#xff0c;最终形成了这个例子。 1、 项目目录&#xff1b; 2、 源码介绍&#xff1b; 1) 初始化&#xff1b; 将样…

高效搭建Nacos:实现微服务的服务注册与配置中心

一、关于Nacos 1.1 简介 Nacos&#xff08;Dynamic Naming and Configuration Service&#xff09;是阿里巴巴开源的一款动态服务发现、配置管理和服务管理平台。它旨在帮助开发者更轻松地构建、部署和管理分布式系统&#xff0c;特别是在微服务架构中。Nacos 提供了简单易用…

112、Qt MSVC编译Qtxlsx

先参考103、QT搭建Excel表环境-使用Qtxlsx库文档&#xff0c;下载xlsx源码以及安装perl环境 并配置VS2019和perl环境变量 Qtxlsx库源码下载&#xff1a;https://github.com/dbzhang800/QtXlsxWriter 解压至非中文路径下 打开Qt自带的MSVC 2019命令框进入文件夹并运行命令生成…

频域滤波为什么使用psf2otf函数?

MATLAB中circshift函数是psf2otf函数的核心&#xff0c;在MATLAB中circshift函数的原理分析——psf2otf函数的核心直观解释了为什么需要循环移位。 MATLAB提出了psf2otf函数&#xff0c;先做循环移位&#xff0c;再计算离散傅里叶变换。如果有空域的卷积核&#xff0c;通过这个…

PySide6 SQLite3 做的 电脑组装报价系统

一、数据库结构说明 1. 配件类别表 (component_categories) 字段名类型说明约束category_idINTEGER类别IDPRIMARY KEY, AUTOINCREMENTcategory_nameTEXT类别名称NOT NULL, UNIQUEdescriptionTEXT类别描述 2. 配件表 (components) 字段名类型说明约束component_idINTEGER配件…

Android 部分操作(待补充

新建的线性布局.xml文件&#xff0c;文件名是 linearlayout.xml&#xff0c;根元素设置LinearLayout&#xff1b; 对于线性布局&#xff0c;调整第一个元素相对于顶部的位置&#xff0c;通过属性 layout_marginTop 设置后调整第一个元素的位置&#xff0c;后边的元素会依次向…

Android笔试面试题AI答之Android基础(7)

Android入门请看《Android应用开发项目式教程》&#xff0c;视频、源码、答疑&#xff0c;手把手教 文章目录 1.Android开发如何提高App的兼容性&#xff1f;**1. 支持多版本 Android 系统****2. 适配不同屏幕尺寸和分辨率****3. 处理不同硬件配置****4. 适配不同语言和地区**…

CSS学习记录21

CSS 工具提示 通过CSS 创建工具提示&#xff08;Tooltip)。 当用户将鼠标指针移动到元素上时&#xff0c;工具提示通常用于提供关于某内容的额外信息&#xff1a; <style> /* Tooltip 容器 */ .tooltip {position: relative;display: inline-block;border-bottom: 1px …

2025经典的软件测试面试题(答案+文档)

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 以下是软件测试相关的面试题及答案&#xff0c;希望对各位能有帮助&#xff01; 1、测试分为哪几个阶段? 一般来说分为5个阶段&#xff1a;单元测试、集成测试…

021-spring-springmvc

比较重要的部分 比较重要的部分 比较重要的部分 关于组件的部分 这里以 RequestMappingHandlerMapping 为例子 默认的3个组件是&#xff1a; org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping org.springframework.web.servlet.mvc.method.annotation.Requ…

Facebook 上的社群文化:连接与共享

随着社交媒体的普及&#xff0c;Facebook作为全球最大的社交平台之一&#xff0c;不仅改变了人们的沟通方式&#xff0c;还塑造了独特的社群文化。在Facebook上&#xff0c;用户可以轻松地与朋友、家人保持联系&#xff0c;同时也能加入兴趣相投的群组、参与讨论和共享内容。社…

语言模型的革命:大型概念模型(LCM)的崛起

在人工智能领域&#xff0c;Meta最近推出的一项重大突破正在引起研究人员和开发者的广泛关注&#xff1a;大型概念模型&#xff08;Large Concept Models&#xff0c;简称LCM&#xff09;。这一创新彻底改变了我们对语言模型的理解&#xff0c;并为未来AI技术的进展指明了新的方…

Python Polars快速入门指南:LazyFrames

前文已经介绍了Polars的Dataframe, Contexts 和 Expressions&#xff0c;本文继续介绍Polars的惰性API。惰性API是该库最强大的功能之一&#xff0c;使用惰性API可以设定一系列操作&#xff0c;而无需立即运行它们。相反&#xff0c;这些操作被保存为计算图&#xff0c;只在必要…

C# 读取多种CAN报文文件转换成统一格式数据,工具类:CanMsgRead

因为经常有读取CAN报文trace文件的需求&#xff0c;而且因为CAN卡不同、记录软件不同会导致CAN报文trace文件的格式都有差异。为了方便自己后续开发&#xff0c;我写了一个CanMsgRead工具类&#xff0c;只要提供CAN报文路径和CAN报文格式的选项即可将文件迅速读取转换为统一的C…

Redis 多机功能 — 复制、Sentinel及集群

Redis 的复制功能通过主从模式实现&#xff0c;允许用户为存储着目标数据库的服务器&#xff08;主服务&#xff09;创建多个拥有相同数据库副本的服务器&#xff08;从服务&#xff09;。让客户端的读请求可以分摊到从服务器中&#xff0c;从而提升性能。复制功能适合对数据一…

计算机网络 (14)数字传输系统

一、定义与原理 数字传输系统&#xff0c;顾名思义&#xff0c;是一种将连续变化的模拟信号转换为离散的数字信号&#xff0c;并通过适当的传输媒介进行传递的系统。在数字传输系统中&#xff0c;信息被编码成一系列的二进制数字&#xff0c;即0和1&#xff0c;这些数字序列能够…

leecode377.组合总和IV

本题其实是多重背包问题&#xff0c;对于价值和重量都是nums[i]的的物品&#xff0c;求装满这个容量为4的背包共有多少种排列方式 如果是组合问题&#xff0c;那么遍历顺序是先物品后背包&#xff0c;这样能保证物品按从小到大顺序依次放置&#xff0c;对于实例1求出来为4&…