MySQL —— Innodb 索引数据结构

news2024/11/12 9:53:40

文章目录

  • 不用平衡二叉树或红黑树作为索引
  • B树适合作为索引
  • 比B树更适合作为索引的结构——B+树
  • 总结

MySQL 使用 B+树索引数据结构(因为默认使用 innodb 存储引擎)

  • B树:有序数组 + 平衡多叉树;
  • B+树:有序数组链表 + 平衡多叉树;

不用平衡二叉树或红黑树作为索引

普通二叉树:

  • 二叉树的查找的时间复杂度是 O ( l o g 2 N ) O(log_2N) O(log2N),其查找效率与深度有关,而普通的二叉树可能由于内部节点排列问题退化成链表。例如,按顺序插入一组递增的数值,可能导致树变成一条链表,在这种情况下,树的深度变为 N,查找的时间复杂度退化为 O ( N ) O(N) O(N),这与链表的查找效率相同。这样查找效率就会很低。
    1
     \
      2
       \
        3
         \
          4
    

平衡二叉树

  • 平衡二叉树是更好的选择,通过自平衡机制保持平衡,即通过旋转调整结构保持最小的深度,所有节点的左右子树高度差不能超过 1,确保了查找、插入和删除操作的时间复杂度保持在 O ( l o g 2 N ) O(log_2N) O(log2N)

为什么平衡二叉树不适合作为索引呢?

  • 索引通常存储在磁盘上的索引文件中。在数据表很大的情况下,索引也会很大,因此无法一次性将全部索引加载到内存当中。数据库系统通常以页(如 4KB、8KB 或 16KB)为单位从磁盘中读取一个磁盘页的数据量到内存中,为了找到指定索引的磁盘页,可能会导致多次磁盘 I/O 操作才能完成。而这个磁盘的读取的速度较内存中的读取速度而言是差了好几个级别,磁盘的随机访问时间可能是内存访问时间的数百倍至数千倍,这意味着每次从磁盘读取数据时,都会消耗较多的时间。

    • 每个节点只有两个子节点,这导致树的高度可能较大。当树的深度增加时,查找时需要的磁盘 I/O 操作也会相应增加。例如,在最坏情况下,查找可能需要访问树的每一层,而每一层都需要从磁盘读取数据。

  • 平衡二叉树在逻辑结构上相近的节点在树的结构中是相邻的,其物理实现是使用数组来存储节点。虽然在逻辑上相邻的节点可能在物理数组中相距较远,因此,每次读取的磁盘页的数据中有许多是用不上的。因此,查找过程中要进行许多次的磁盘读取操作。

    • 平衡二叉树各节点之间在逻辑上存在一定的关系,但在物理实现却是随机的,比如父子关系或兄弟关系的两个节点子逻辑上相邻之类的,但在物理实现上却是分散的。对于使用磁盘预读(局部性原理),每次从磁盘读取一页,读取的是物理结构上连续的一段数据,这样就会读取许多无用的信息(接下来很大机会不会用到);

    • 其次就是二叉树每个节点只能存储一个关键字及其相关信息,不能充分利用磁盘预读功能;

  • 而适合作为索引的结构应该是尽可能少的执行磁盘IO操作,因为执行磁盘IO操作非常的耗时。因此,平衡二叉树并不适合作为索引结构。

总结:

  • 使用红黑树(平衡二叉树)结构的话,每次磁盘预读中的很多数据是用不上的数据。因此,它没能利用好磁盘预读的提供的数据。
  • 然后又由于深度大(较B树而言),所以进行的磁盘IO操作更多。

B树适合作为索引

平衡二叉树没能充分利用磁盘预读功能,而B树是为了充分利用磁盘预读功能来而创建的一种数据结构,也就是说B树就是为了作为索引才被发明出来的的。

  • B 树的设计旨在最大限度地减少磁盘访问次数,特别是在处理大量数据时。由于磁盘访问速度远低于内存访问速度,减少 I/O 操作对于提高整体性能至关重要;
  • B 树结构允许每个节点包含多个关键字和子节点,这意味着在一次磁盘读取中可以获取更多的数据。这样,B树能够高效地利用磁盘的读取特性,特别是在顺序访问时;

B树的结构特点

  • 多叉结构:与平衡二叉树不同,B 树的每个节点可以有多个子节点,这使得树的高度显著降低,从而减少了查找和更新时所需的 I/O 操作;
  • 节点内存储多个关键字:B 树的每个节点可以存储多个关键字,这样在每次读取磁盘页时,可以同时获取多个数据项,充分利用了磁盘的预读能力;

局部性原理与磁盘预读:

  • 由于存储介质的特性,磁盘的存取速度远低于内存,传统机械硬盘的访问时间受机械运动的影响,磁盘的存取速度往往是主存的几百分分之一,这使得磁盘 I/O 成为性能瓶颈,尤其是在需要频繁读取数据时。因此为了提高效率,要尽量减少磁盘 I/O。为了达到这个目的,磁盘读取往往不是严格按需读取,而是每次都会预读,读取一段连续的数据(称为一页),即使只需要一个字节,磁盘也会从这个位置开始,顺序向后读取一定长度的数据放入内存。这样做的目的是利用磁盘的顺序读取特性,提高读取效率。这样做的理论依据是计算机科学中著名的局部性原理;

  • 局部性原理:局部性原理是指在程序运行过程中,访问的数据往往集中在某些特定区域。当一个数据项被访问时,其附近的数据项很可能也会被访问。这种现象在许多程序中普遍存在。由于磁盘顺序读取的效率很高(不需要寻道时间,只需很少的旋转时间),因此对于具有局部性的程序来说,预读可以提高I/O效率;

    在操作系统中,磁盘 I/O 的读取和写入通常以页(page)为单位进行。页是固定大小的数据块,一页的数据量有多大跟操作系统有关,常见的大小有 4KB、8KB 或 16KB。也就是我们读取一页内的数据时候,实际上才发生了一次IO,这个理论对于索引的数据结构设计非常有帮助;

  • 磁盘预读是具体实现,其理论依据是局部性原理。

B树适合作为索引

B 树的每个节点可以存储多个关键字,它将节点大小设置为磁盘页的大小,充分利用了磁盘预读的功能。每次读取磁盘页时就会读取一整个节点。也正因每个节点存储着非常多个关键字,树的深度就会非常的小。进而要执行的磁盘读取操作次数就会非常少,更多的是在内存中对读取进来的数据进行查找。

  • 每个节点可以存储多个关键字,可以充分利用了磁盘预读的功能;
  • B 树的深度会非常的小,减小磁盘 I/O 操作。

B树的查询,主要发生在内存中,而平衡二叉树的查询,则是发生在磁盘读取中。因此,虽然B树查询查询的次数不比平衡二叉树的次数少,但是相比起磁盘IO速度,内存中比较的耗时就可以忽略不计了。因此,B树更适合作为索引。

比B树更适合作为索引的结构——B+树

B+树中的B不是代表二叉(binary),而是代表平衡(balance),因为B+树是从最早的平衡二叉树演化而来,但是 B+树不是一个二叉树。

MySQL 中也是使用B+树作为索引。它是B树的变种,因此是基于B树来改进的。

B+树的关键字全部存放在叶子节点中,非叶子节点用来做索引,而叶子节点中有一个指针指向一下个叶子节点。做这个优化的目的是为了提高区间访问(遍历)的性能。

  • B树必须用中序遍历的方法按序扫库,而B+树直接从叶子结点挨个扫一遍就完了,B+树支持 range-query 非常方便,而B树不支持。这是数据库选用B+树的最主要原因。

    比如说:

    我们要查找关键字范围在3到7的关键字,在找到第一个符合条件的数字3后,访问完第一个关键字所在的块后,得遍历这个B树,获取下一个块,直到遇到一个不符合条件的关键字。遍历的过程是比较复杂的。(即B树遍历完一块后,需要查询B树得到下一块,然后再遍历)
    
    相比之下,B+树的基于范围的查询简洁很多。由于叶子节点有指向下一个叶子节点的指针,因此从块1到块2的访问,通过块1指向块2的指针即可,从块2到块3也是通过一个指针即可。(B+树遍历完一块后,可以通过指针指向下一块继续遍历)
    
  • B+树只要遍历叶子节点就可以实现整棵树的遍历。而且在数据库中基于范围的查询是非常频繁的,而B树不支持这样的操作(或者说效率太低)。

b+树的查找过程:

  • 如图所示,如果要查找数据项29,那么首先会把磁盘块1由磁盘加载到内存,此时发生一次IO,在内存中用二分查找确定29在17和35之间,锁定磁盘块1的P2指针,内存时间因为非常短(相比磁盘的IO)可以忽略不计,通过磁盘块1的P2指针的磁盘地址把磁盘块3由磁盘加载到内存,发生第二次IO,29在26和30之间,锁定磁盘块3的P2指针,通过指针加载磁盘块8到内存,发生第三次IO,同时内存中做二分查找找到29,结束查询,总计三次IO。真实的情况是,3层的b+树可以表示上百万的数据,如果上百万的数据查找只需要三次IO,性能提高将是巨大的,如果没有索引,每个数据项都要发生一次IO,那么总共需要百万次的IO,显然成本非常非常高。
    在这里插入图片描述

    一颗b+树,浅蓝色的块我们称之为一个磁盘块,可以看到每个磁盘块包含几个数据项(深蓝色所示)和指针(黄色所示),如磁盘块1包含数据项17和35,包含指针P1、P2、P3,P1表示小于17的磁盘块,P2表示在17和35之间的磁盘块,P3表示大于35的磁盘块。真实的数据存在于叶子节点即3、5、9、10、13、15、28、29、36、60、75、79、90、99。非叶子节点不存储真实的数据,只存储指引搜索方向的数据项,如17、35并不真实存在于数据表中。

总结:用B+树的主要原因是B树在提高了磁盘IO性能的同时并没有解决元素遍历的效率低下的问题。正是为了解决这个问题,B+树应运而生。

总结

B树:

  • B树就是一个节点可以拥有多于2个子节点的多叉查找树。

  • 叶子节点和非叶子节点都储存关键字和真实数据项,每个节点不仅用于索引,还包含实际的数据。因为非叶子节点要保存数据项,所以一个节点(块)能保存的索引少,相对于B+树访问磁盘IO时就多;

  • B树是有序数组+平衡多叉树;

B+树:

  • B+树是基于B树来改进的。

  • 非叶子节点只存储关键字,用于索引搜索路径,而不存储实际的数据项,所有真实数据只存储在叶子节点中。因为非叶子节点不保存数据项,所以一个节点(块)能保存的索引多,相对于B树访问磁盘IO时就少,尽管在内存遍历的次数变多,但内存访问比磁盘快很多,相对于访问磁盘,访问内存的时间几乎可以不计。

  • B+树:有序数组链表+平衡多叉树;

    树的所有叶子节点构成一个有序链表,可以按照主键排序的次序遍历全部记录。B+Tree 所有真实数据都在叶子节点上,并且增加了顺序访问指针,每个叶子节点都有指向相邻叶子节点的指针,便于区间查找和遍历。

B树与B+树对比:

  • B树结构在所有的节点里存储索引信息和数据项;B+树结构没有在所有的节点里存储记录数据项,而是只在最下层的叶子节点存储,上层的所有非叶子节点只存放索引信息。
  • B树是有序数组+平衡多叉树;B+树是有序数组链表+平衡多叉树。B+树使用双向链表串连所有叶子节点,区间查询效率更高,因为所有数据都在B+树的叶子节点,但是B树则需要通过中序遍历才能完成查询范围的查找。
  • B+树每次都必须查询到叶子节点才能找到数据,而B树查询的数据可能不在叶子节点,也可能在,这样就会造成查询的效率的不稳定。
  • B+树查询效率更高,因为B+树矮更胖,高度小,查询产生的I/O最少。因为非叶子节点不保存数据项,所以一个节点(块)能保存的关键字(索引)更多,所以一次性读入内存中的需要查找的关键字也就越多。相对来说IO读写次数也就降低了。

B+ 树的优点在于:

  • IO次数更少(相对于其他数据结构):由于B+树在内部节点上不包含数据信息,因此在内存页中能够存放更多的key。 数据存放的更加紧密,具有更好的空间局部性。因此访问叶子节点上关联的数据也具有更好的缓存命中率。
    • 数据库系统的设计者巧妙利用了磁盘预读原理,将一个节点的大小设为等于一个页,这样每个节点需要一次I/O就可以完全载入。
  • 遍历更加方便(相对于B树结构):B+树的叶子结点都是相链的,因此对整棵树的遍历只需要一次线性遍历叶子结点即可。而且由于数据顺序排列并且相连,所以便于区间查找和搜索。而B树则需要进行每一层的递归遍历。相邻的元素可能在内存中不相邻,所以缓存命中性没有B+树好。
    • 这样做是为了提高区间效率,例如查询key为从18到49的所有数据记录,当找到18后,只要顺着节点和指针顺序遍历就可以以此向访问到所有数据节点,极大提高了区间查询效率。

B树优点:

  • 但是B树也有优点,其优点在于,由于B树的每一个节点都包含key和value,因此经常访问的元素可能离根节点更近,因此访问也更迅速。下面是B 树和B+树的区别图:
    在这里插入图片描述

为什么MySQL选择B+树做索引

1、 B+树的磁盘读写代价更低:B+树的内部节点并没有指向关键字具体信息的指针,因此其内部节点相对B树更小,如果把所有同一内部节点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多,一次性读入内存的需要查找的关键字也就越多,相对IO读写次数就降低了。

2、B+树的查询效率更加稳定:由于非终结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当。

3、B+树更便于遍历:由于B+树的数据都存储在叶子结点中,分支结点均为索引,方便扫库,只需要扫一遍叶子结点即可,但是B树因为其分支结点同样存储着数据,我们要找到具体的数据,需要进行一次中序遍历按序来扫,所以B+树更加适合在区间查询的情况,所以通常B+树用于数据库索引。

4、B+树更适合基于范围的查询:B树在提高了IO性能的同时并没有解决元素遍历的我效率低下的问题,正是为了解决这个问题,B+树应用而生。B+树只需要去遍历叶子节点就可以实现整棵树的遍历。而且在数据库中基于范围的查询是非常频繁的,而B树不支持这样的操作或者说效率太低。

参考1

参考2

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

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

相关文章

安信金业:3d黄金跟999足金的区别

黄金饰品,作为一种永恒的象征,一直备受人们的喜爱。随着工艺技术的不断革新,黄金饰品也呈现出多元化的风格。近年来,3D硬金逐渐走入人们的视野,与传统的999足金形成了鲜明的对比。那么,3D硬金和999足金究竟…

Mac如何实现最简单的随时监测实时运行状态的方法

Mac book有着不同于Windows的设计逻辑与交互设计,使得Mac book有着非常棒的使用体验,但是在Mac电脑的使用时间过长时,电脑也会出现响应速度变慢或应用程序崩溃的情况,当发生的时候却不知道什么原因导致的,想要查询电脑…

c语言其实很简单----【数组】

TOC 1.输入10个学生成绩&#xff0c;计算及格人数&#xff0c;平均成绩&#xff0c;总成绩。 #include<stdio.h> int main(){float score[10];int i ,cut;float avar0.0,sum0.0;for(i0;i<10;i)scanf("%f",&score[i]);//输入10个学生的成绩cut0;for(i0…

音视频入门基础:H.264专题(22)——通过FFprobe显示H.264裸流每个packet的信息

音视频入门基础&#xff1a;H.264专题系列文章&#xff1a; 音视频入门基础&#xff1a;H.264专题&#xff08;1&#xff09;——H.264官方文档下载 音视频入门基础&#xff1a;H.264专题&#xff08;2&#xff09;——使用FFmpeg命令生成H.264裸流文件 音视频入门基础&…

centos7的maven配置

首先进入conf配置文件夹下的setting.xml 要改两个地方 第一&#xff1a;设置镜像源 <mirror> <id>alimaven</id> <name>aliyun maven</name> <url>https://maven.aliyun.com/nexus/content/groups/public/</url> <mirrorOf>c…

【优选算法 — 滑动窗口】滑动窗口小专题(一)

长度最小的子数组 长度最小的子数组 题目解析&#xff1a; 对于示例一 对于剩下两种示例&#xff1a; 解法一&#xff1a;暴力枚举 把所有的子数组全部枚举出来&#xff0c;并且枚举出的每一个子数组求和判断&#xff0c;返回长度最小的子数组&#xff1b; 时间复杂度 &…

从零创建vue+elementui+sass+three.js项目

初始化&#xff1a; vue init webpack projectnamecd projectnamenpm install支持sass: npm install sass --save-dev npm install sass-loader7.1.0 --save-dev npm install node-sass4.12.0 --save-devbuild/webpack.base.conf.js添加 rules: [...,{test: /\.scss$/,loade…

Golang--网络编程

1、概念 网络编程&#xff1a;把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大、功能强的网络系统&#xff0c;从而使众多的计算机可以方便地互相传递信息、共享数据、软件、数据信息等资源。 客户端&#xff08;Client&#xff09; 客户端是请求服务…

RNN(循环神经网络)详解

1️⃣ RNN介绍 前馈神经网络&#xff08;CNN&#xff0c;全连接网络&#xff09;的流程是前向传播、反向传播和参数更新&#xff0c;存在以下不足&#xff1a; 无法处理时序数据&#xff1a;时序数据长度一般不固定&#xff0c;而前馈神经网络要求输入和输出的维度是固定的&a…

Parallax.js:让智能设备视差效果更智能、更自然

今天给大家分享一款功能非常强大的javascript视觉差特效引擎插件&#xff1a;Parallax.js。 Parallax.js简介 Parallax.js是一个简单的&#xff0c;轻量级的视差引擎。你可以将它作为作为jQuery或Zepto插件来使用&#xff0c;也可以以纯JS的方式来使用。 最-最-最厉害的是它…

【三维重建】Semantic Gaussians:开放词汇的3DGS场景理解

文章目录 摘要一、引言二、主要方法1.3D Gaussian Splatting2.其他方法2.1 Gaussian Grouping&#xff08;ECCV 2024&#xff09;2.2 GARField 3. 2D Versatile 投影4. 3D Semantic Network4. 推理 四、实验1. 实验设置2.定量结果 论文&#xff1a;https://arxiv.org/pdf/2403.…

【功能介绍】信创终端系统上各WPS版本的授权差异

原文链接&#xff1a;【功能介绍】信创终端系统上各WPS版本的授权差异 Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇关于信创终端操作系统上WPS Office各版本&#xff08;不包括政务版、企业版等&#xff09;之间的差异的文章。WPS Office作为国内广泛使用的办公软…

Elmo驱动器上位机软件的详细配置

续接上文,本文讲解Elmo驱动器上位机软件更详细的配置,重点关注,在电机的位置受到约束的情况下,完成驱动器的参数整定过程,以及一些调试方法 一 硬件介绍 本文使用的是另一套设备,假设电机的位置是受到约束的 1 编码器规格书 编码器已知信息是 :读数头是26位的,通讯…

「Mac畅玩鸿蒙与硬件32」UI互动应用篇9 - 番茄钟倒计时应用

本篇将带你实现一个番茄钟倒计时应用&#xff0c;用户可以设置专注时间和休息时间的时长&#xff0c;点击“开始专注”或“开始休息”按钮启动计时&#xff0c;应用会在倒计时结束时进行提醒。番茄钟应用对于管理时间、提升工作效率非常有帮助&#xff0c;并且还会加入猫咪图片…

SparkSql读取数据的方式

一、读取普通文件 方式一&#xff1a;给定读取数据源的类型和地址 spark.read.format("json").load(path) spark.read.format("csv").load(path) spark.read.format("parquet").load(path) 方式二&#xff1a;直接调用对应数据源类型的方法 …

模型训练中GPU利用率低?

买了块魔改华硕猛禽2080ti&#xff0c;找了下没找到什么测试显存的软件&#xff0c;于是用训练模型来测试魔改后的显存稳定性&#xff0c;因为模型训练器没有资源监测&#xff0c;于是用了Windows任务管理器来查看显卡使用情况&#xff0c;却发现GPU的利用率怎么这么低&#xf…

在gitlab,把新分支替换成master分支

1、备份master分支&#xff0c;可以打tag 2、删除master分支 正常情况下&#xff0c;master分支不允许删除&#xff0c;需要做两个操作才能删除 a、变更项目默认分支为非master分支&#xff0c;可以先随便选择 b、取消master为非保护分支 操作了上述两步&#xff0c;就可以删…

Transformer究竟是什么?预训练又指什么?BERT

目录 Transformer究竟是什么? 预训练又指什么? BERT的影响力 Transformer究竟是什么? Transformer是一种基于自注意力机制(Self-Attention Mechanism)的神经网络架构,它最初是为解决机器翻译等序列到序列(Seq2Seq)任务而设计的。与传统的循环神经网络(RNN)或卷…

UE5.4 PCG 自定义PCG蓝图节点

ExecuteWithContext&#xff1a; PointLoopBody&#xff1a; 效果&#xff1a;点密度值与缩放成正比

SLF4J: Failed to load class “org.slf4j.impl.StaticLoggerBinder”

SLF4J常见问题 1、SLF4J简介2、SLF4J实现原理3、SLF4J常见问题 1、SLF4J简介 SLF4J&#xff08;Simple Logging Facade for Java&#xff09;是一个为Java程序提供日志输出的统一接口&#xff0c;并不具备具体的日志实现方案&#xff0c;类似JDBC&#xff0c;SLF4J只做两件事&a…