为什么MySQL使用B+树索引,而不使用其他作为索引呢?

news2024/11/6 17:29:29

索引介绍

索引是一种用于快速查询和检索数据的数据结构,其本质可以看成一种排序号的数据结构

索引的作用相当于书的目录。打个比方:在查字典的时候,如果没有目录,那我们就只能一页一页地去查,速度很慢。如果有目录,我们只需要先去目录里查找字的位置,然后直接翻到那一页就行了。

索引底层数据结构存在很多种类型,常见的索引结构有:B树、B+树、Hash、红黑树。在 MySQL 中,无论是 Innodb 还是 MyIsam ,都使用了 B+树 作为索引结构。


索引的优缺点

优点:

  • 使用 索引 可以大大加快数据的检索速度(大大减少检索的数据量)
  • 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性

缺点:

  • 创建索引和维护索引需要耗费很多时间。当对表中的数据进行增删改查的时候,如果数据有索引,那么索引也需要动态的修改,会降低 SQL 执行效率。
  • 索引需要使用物理文件存储,也会耗费一定空间

索引底层数据结构

Hash 表

哈希表是键值对的集合,通过即可快速取出对应的 ,因此哈希表可以快速地检索数据(接近O(1))。

#  构造散列函数
def hash(a):
    return (a % 8) ^ 7

类似的hash算法如上,通过异或或者移位的方式使得计算结果的规律性不那么明显,增加 hash 算法的可靠性

但是,哈希算法有一个 hash冲突 的问题,也就是说多个不同的 key(a) 最后得到的 index 可能相同。通常情况下,解决办法是 链地址法 ,即将哈希冲突的数据存放在链表中。

HashMap 就是一种常见的 采用 hash 表存储数据的结构(下图为jdk1.8之前的版本,jdk1.8之后的版本在此基础上加入了 红黑树 来解决链表过长带来的查询缓慢问题

既然 哈希表 这么快,为什么 MySQL 没有使用其作为索引的数据结构呢?

主要是因为 Hash 索引是无序的,不支持顺序和范围查询。假如我们需要对表中的数据进行排序或者范围查询的时候,Hash 索引就不可行了。并且每次 IO 只能取一个。

SELECT * FROM tb1 WHERE id < 500;

在这种范围查询中,直接遍历比500小的叶子节点就够了。而使用 Hash 索引是根据 hash 算法来定位的,不能确保 存储的顺序。


二叉查找树(BST)

二叉查找树 是一种基于二叉树的数据结构,有以下特点:

  1. 左子树的所有节点的值均小于根节点的值
  2. 右子树的所有节点的值均大于根节点的值
  3. 左右子树页分别为二叉查找树

当二叉查找树是平衡的时候,也就是树的每个节点的左右子树深度相差不超过 1 的时候,查询的时间复杂度为 O(log2(N)),具有比较高的效率。然而 ,当二叉查找树不平衡时,例如在最坏情况下(有序插入节点),树会退化成线性链表(也称为斜树),导致查询效率急剧下降,时间复杂度退化为 O(N)

二叉查找树的性能非常依赖于它的平衡度,这就导致其不适合作为 MySQL 底层索引的数据结构


AVL树 (平衡二叉树)

AVL树的特点是保证任何节点的左右子树高度之差不超过 1 ,因此也被称为高度平衡二叉树,它的查找、插入和删除在平均和最坏情况下的时间复杂度都是 O(logn)。

AVL树采用了旋转操作来保持平衡。主要有四种旋转操作:LL旋转、RR旋转、LR旋转和RL旋转。其中LL旋转和RR旋转分别用于处理左左和右右失衡,而LR旋转 和 RL旋转 用于处理左右和右左失衡。

由于 AVL 树需要频繁地进行旋转操作来保持平衡,因此会有较大的计算开销进而降低了查询的性能。并且,在使用 AVL 树时,每个树节点仅存储一个数据,而每次进行磁盘 IO 时只能读取一个节点的数据,如果需要查询的数据分布在多个节点上,那么就需要进行多次磁盘 IO。磁盘IO是一项耗时的操作,在设计数据库索引时,我们需要优先考虑如何最大限度地减少磁盘 IO 操作的次数

除此之外,随着数据的增多,树的高度也会变高,这就意味着磁盘 IO 操作次数增多,会影响整体数据查询的效率。

比如,上图的平衡二叉树的高度为 5 ,那么在访问最底部的节点时,就需要 5 次 磁盘 IO 操作。根本原因是因为它们都是二叉树,也就是每个节点只能保存两个子节点


B 树

AVL 树虽然能保持查询操作的时间复杂度在 O(logn),但是因为它本质上是一个二叉树,每个节点只能存储 2 个子节点,那么当节点个数越多的时候,树的高度也会相应变高,这样就会增加磁盘的 IO次数,从而影响数据查询的效率。

为了解决降低树的高度的问题,就引出了 B 树,它不再限制一个节点只能有 2 个 子节点,而是允许 M 个子节点,从而降低 树的高度

假设 M = 3 ,那么就是一颗 3 阶的 B 树,特点就是每个节点最多有 2 个 (M-1个)数据和最多有 3 个(M 个)子节点,超过这些要求的话就会分裂节点:

 

假设我们在下面这幅 B 树中查找的索引值是 9 的记录

那么步骤可以分为以下几步:

  • 与根节点的索引(4,8)进行比较,9 > 8 所以查询最右边的子节点
  • 然后该子节点的索引为 (10,12),9 < 10 所以查询该节点的最左边的子节点
  • 找到索引值为 9 的节点。

可以看到 ,一颗 3 阶的 B 树在查询叶子节点中的数据时,由于树的高度是 3 ,所以在查询过程中会发生 3 次磁盘 IO 操作。

而同样的数据放在平衡二叉树下,树的高度就会很高,意味着磁盘 IO 操作会更多。所以 B 树在数据查询中比平衡二叉树的效率高

但是 B 树的每一个节点都包含数据(索引 + 记录) ,而用户的记录数据的大小很有可能远远超做过了索引数据,这就需要花费更多的 磁盘 IO 操作次数来读到 有用的索引数据。

而且在我们查询位于叶子节点上的数据的时候,其父节点以及之前的节点的数据也会加载到磁盘内存,但是这些数据时没有用的,我们只想获取最终节点上的数据,而不是查询过程中遍历过的节点的数据。所以使用 B 树作为索引的话会占用大量内存资源(这些资源本不应该被占用)

另外,如果使用 B 树来做范围查询的话,需要使用中序遍历,这会涉及到多个节点的磁盘 IO 问题一,从而导致整体速度下降。


B+树

B+树就是对 B 树做了一个升级,MySQL 中索引的数据结构就是采用的 B+树:

B+树和 B 树差异的点,主要是以下几个点:

  • 叶子节点才会存放实际数据,非叶子节点只能存放索引
  • 所有索引都会在叶子节点出现,叶子节点之间构成一个有序链表(在mysql中是双向链表)
  • 非叶子节点的索引会同时存在于子节点中,并且是在子节点中最大或者最小
  • 非叶子节点中有多少个子节点,就有多少个索引

查询效率:

B+树的非叶子节点不存放实际的记录数据,仅存放索引,因此数据量相同的情况下,相比存储索引又存储记录的 B 树, B+树的非叶子节点可以存放更多的索引,因此 B+ 树可以比 B 树更 [矮胖] ,查询底层节点的磁盘 IO 次数会更少

插入和删除效率:

B+ 树有大量的冗余节点,这导致删除一个节点的时候,可以直接从叶子节点中删除,甚至不需要动非叶子节点。

B+ 树的插入操作也是一样,由于有冗余节点,插入可能存在节点的分裂(节点饱和的话)但是最多只涉及树的一条路径。而且 B+树会自动平衡,不需要做更多复杂的操作

范围查询:

由于 B+树所有的叶子节点搜集通过链表进行连接,这种设计可以帮助我们更直接地获取范围内的数据,直接遍历链表即可,而不需要像B树那样,去遍历树。

在 Mysql 中 innoDB 存储引擎采用的就是 B+树作为索引的数据结构,但是在其基础上加了些改进:

  • InnoDB存储引擎中 叶子节点是通过双向链表进行连接的,这使得范围查询更加方便,既能向右遍历也能向左遍历
  • B+ 树的节点内容是数据页,数据页中存放了用户的记录以及各种信息,每个数据页的大小默认是 16KB


总结

二分查找树虽然是一个天然的二分结构,能很好的利用二分查找快速定位数据,但是它存在一种极端的情况,每当插入的元素都是树内最大的元素,就会导致二分查找树退化成一个链表,此时查询复杂度就会从 O(logn)降低为 O(n)。

了解决二分查找树退化成链表的问题,就出现了自平衡二叉树,保证了查询操作的时间复杂度就会一直维持在 O(logn) 。但是它本质上还是一个二叉树,每个节点只能有 2 个子节点,随着元素的增多,树的高度会越来越高。

而树的高度决定于磁盘 I/O 操作的次数,因为树是存储在磁盘中的,访问每个节点,都对应一次磁盘 I/O 操作,也就是说树的高度就等于每次查询数据时磁盘 IO 操作的次数,所以树的高度越高,就会影响查询性能

B 树和 B+ 都是通过多叉树的方式,会将树的高度变矮,所以这两个数据结构非常适合检索存于磁盘中的数据。

但是 MySQL 默认的存储引擎 InnoDB 采用的是 B+ 作为索引的数据结构,原因有:

  • B+ 树的非叶子节点不存放实际的记录数据,仅存放索引,因此数据量相同的情况下,相比存储即存索引又存记录的 B 树,B+树的非叶子节点可以存放更多的索引,因此 B+ 树可以比 B 树更「矮胖」,查询底层节点的磁盘 I/O次数会更少。
  • B+ 树有大量的冗余节点(所有非叶子节点都是冗余索引),这些冗余索引让 B+ 树在插入、删除的效率都更高,比如删除根节点的时候,不会像 B 树那样会发生复杂的树的变化;
  • B+ 树叶子节点之间用链表连接了起来,有利于范围查询,而 B 树要实现范围查询,因此只能通过树的遍历来完成范围查询,这会涉及多个节点的磁盘 I/O 操作,范围查询效率不如 B+ 树。

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

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

相关文章

怎么把图片转换成ico图标文件?

环境&#xff1a; Win10 专业版 问题描述&#xff1a; 怎么把图片转换成ico图标文件 解决方案&#xff1a; 要将图片转换为 ico 图标文件&#xff0c;可以使用以下几种方法&#xff1a; 方法 1&#xff1a;使用在线转换器 1.访问在线 ico 转换器&#xff0c;例如&#xf…

others-AppLovin广告接入

title: others-AppLovin广告接入 categories: Others tags: [广告, AppLovin] date: 2023-10-20 10:07:01 comments: false mathjax: true toc: true others-AppLovin广告接入 前篇 官方 - https://www.applovin.com/ Android sdk - https://github.com/AppLovin/AppLovin-MAX…

03-Android App logger策略

背景 经常会为log定位而烦恼。比如&#xff1a;同一个类&#xff0c;一样的log输出&#xff0c;无法定位到Log输出的行。 方案 1.java StackTraceElement 通过java StackTraceElement获取类名&#xff0c;以及log输出行 2. 具体实现 NonNullprivate static String getSour…

基于金枪鱼群优化的BP神经网络(分类应用) - 附代码

基于金枪鱼群优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码 文章目录 基于金枪鱼群优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码1.鸢尾花iris数据介绍2.数据集整理3.金枪鱼群优化BP神经网络3.1 BP神经网络参数设置3.2 金枪鱼群算法应用 4.测试结果…

FreeRTOS入门教程(互斥锁的概念和函数使用)

文章目录 前言一、互斥锁的概念二、互斥锁相关函数三、使用互斥锁完成同步四、FreeRTOS中互斥锁存在的问题五、优先级反转和优先级继承六、死锁七、递归锁总结 前言 本篇文章带大家学习什么是互斥锁&#xff0c;并且学习一下互斥锁中一些函数的使用方法。 一、互斥锁的概念 …

修改java项目启动后在jps展示的名称

文章目录 问题在服务器上启动jar包的时候,通过jps查看java进程只展示个 jar解决,指定jar包的全路径jps查看maven打包修改jar名称 问题在服务器上启动jar包的时候,通过jps查看java进程只展示个 jar 解决,指定jar包的全路径 java -jar /root/test/aaa.jarjps查看 494976 aaa.ja…

OpenCV实现物体尺寸的测量

一 &#xff0c;项目分析 物体尺寸测量的思路是找一个确定尺寸的物体作为参照物&#xff0c;根据已知的计算未知物体尺寸。 如下图所示&#xff0c;绿色的板子尺寸为220*300&#xff08;单位&#xff1a;毫米&#xff09;&#xff0c;通过程序计算白色纸片的长度。 主要是通过…

DatenLord前沿技术分享 No.38

达坦科技专注于打造新一代开源跨云存储平台DatenLord&#xff0c;通过软硬件深度融合的方式打通云云壁垒&#xff0c;致力于解决多云架构、多数据中心场景下异构存储、数据统一管理需求等问题&#xff0c;以满足不同行业客户对海量数据跨云、跨数据中心高性能访问的需求。在本周…

WebGIS面试(第二期)

一、简介 近期看到好多小伙伴在寻找WebGIS方面的面试题&#xff0c;正好本人之前也因自己面试分享过一些面试题&#xff0c;秋招目前逐步也快结束了&#xff0c;所以我现在慢慢整理一些包括自己面试以及网上公开的一些我认为有用的面试题&#xff0c;仅供参考&#xff0c;大多…

吃鸡游戏出现msvcp140.dll缺失的四个解决方法

首先&#xff0c;让我们了解一下什么是MSVCP140.dll。MSVCP140.dll是Microsoft Visual C 2015 Redistributable Package的一部分&#xff0c;它是一组C库文件&#xff0c;用于支持使用Visual Studio 2015开发的应用程序。如果你的程序需要这些库文件来正常运行&#xff0c;那么…

结构体内存对齐规则

✨前言✨ &#x1f4d8; 博客主页&#xff1a;to Keep博客主页 &#x1f646;欢迎关注&#xff0c;&#x1f44d;点赞&#xff0c;&#x1f4dd;留言评论 ⏳首发时间&#xff1a;2023年10月20日 &#x1f4e8; 博主码云地址&#xff1a;博主码云地址 &#x1f4d5;参考书籍&…

【量化交易笔记】10.建立最简单的交易策略

概述 量化说得简单一些用策略进行股票交易&#xff0c;在实施交易之前&#xff0c;需要制定策略&#xff0c;并回测试共效果 为了把交易说明清楚&#xff0c;将这个过程&#xff0c;能简单&#xff0c;就简单&#xff0c;总之&#xff0c;简单&#xff0c;简单再简单。 以下主…

NodeJS的初使用,以及引入第三方插件和安装淘宝镜像的教程

NodeJs 命令 npm init -y 生成package.json文件npm i jquery --save–dev 开发依赖(jQuery后面还可以跟模块,可以有多个)npm i jquery --save 生产依赖npm i jquery --D 开发依赖npm uninstall jquery 卸载删除npm i 把删掉的模块,全部重新加载回来 1.介绍 1.什么是NodeJs?…

SystemVerilog Assertions应用指南 Chapter 1.16“ended”结构

1.16“ended”结构 到目前为止,定义的序列都只是用了简单的连接( concatenation)的机制。换句话说,就是将多个序列以序列的起始点作为同步点,来组合成时间上连续的检查。SVA还提供了另种使用序列的结束点作为同步点的连接机制。这种机制通过给序列名字追加上关键词“ ended”来…

python二次开发Solidworks:修改实体尺寸

立方体原始尺寸&#xff1a;100mm100mm100mm 修改后尺寸&#xff1a;10mm100mm100mm import win32com.client as win32 import pythoncomdef bin_width(width):myDimension Part.Parameter("D1草图1")myDimension.SystemValue width def bin_length(length):myDime…

OpenGL —— 2.6、绘制一个正方体并贴图(附源码,glfw+glad)

源码效果 C源码 纹理图片 需下载stb_image.h这个解码图片的库&#xff0c;该库只有一个头文件。 具体代码&#xff1a; vertexShader.glsl #version 330 corelayout(location 0) in vec3 aPos; layout(location 1) in vec2 aUV;out vec2 outUV;uniform mat4 _viewMatrix; u…

手帐怎么做?推荐这10款手帐达人都在用的好用软件!

手帐是一种强大的可视化方式&#xff0c;可以记录你的观察、日常的思考&#xff0c;并随时间的推移来衡量你的进步。在各种手帐软件的帮助下&#xff0c;创建并完全自定义你的手帐变得比以往任何时候都更容易。 有无数的手帐软件可供选择&#xff0c;满足各种需求。但在众多的…

基于Java的勤工助学管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…

京东数据分析:2023年9月京东洗烘套装品牌销量排行榜!

鲸参谋监测的京东平台9月份洗烘套装市场销售数据已出炉&#xff01; 根据鲸参谋平台的数据显示&#xff0c;今年9月份&#xff0c;京东平台洗烘套装的销量为7100&#xff0c;环比下降约37%&#xff0c;同比增长约87%&#xff1b;销售额为6000万&#xff0c;环比下降约48%&#…

使用Spyder进行动态网页爬取:实战指南

导语 知乎数据的攀爬价值在于获取用户观点、知识和需求&#xff0c;进行市场调查、用户画像分析&#xff0c;以及发现热门话题和可能的新兴领域。同时&#xff0c;知乎上的问题并回答也是宝贵的学习资源&#xff0c;用于知识图谱构建和自然语言处理研究。爬取知乎数据为决策和…