Mysql系列 -索引模型数据结构

索引就是排好序的数据结构,可以帮助我们快速的查找到数据,那么底层的数据到底是如何存储的呢?

为什么InnoDB 用的是B+tree 存储结构?

大家可以看看这个可视化的网站
数据结构和算法的可视化工具
在这里插入图片描述
可以看到数据结构里面有链表,二叉树,AVL,红黑树,Hash,B tree ,B+tree等等,可以点击进入每个数据结构的可视化页面,玩一玩,看看插入时数据是怎么样排序的

1.二叉查找树(Binary Search Trees)

二叉树的特点是左边节点比右边节点小,每个叶子节点下的子节点最多只能有2个,每次插入都会先比较根节点,小的往左边,大的往右边。
在这里插入图片描述

缺点
由于只能有2个叶子节点,所以数据量大的时候树的层级会非常高,而且当插入的数据都是有序的,如下图,就会造成斜树,这样就退化成有序链表了
在这里插入图片描述

2.平衡搜索二叉树(AVL trees)

解决了斜树的问题,每次插入是时候节点会进行旋转,左小右大,减少了树的高度,非叶子节点最多拥有2个叶子节点,同时树的左右2边层级 相差不会大于1;
在这里插入图片描述

右旋LL:当想左边节的左子节点点插入数据,例如插入10,8,6的时候,为了保持树的平衡,会把10节点进行右旋,试树能够平衡
在这里插入图片描述
左旋RR:当想右边节的右子节点点插入数据,例如插入10,12,14的时候,为了保持树的平衡,会把10节点进行左旋,试树能够平衡

在这里插入图片描述

缺点
虽然解决了斜树的问题,但是还是会造成树的层级太高,每个叶子节点只能有2个子节点,查询的时候会造成IO次数太多

3.红黑树(Red-Black Trees)

在这里插入图片描述

网上有大牛总结了个顺口溜:根节点必黑,新增是红色,只能黑连黑,不能红连红; 爸叔通红就变色,爸红叔黑就旋转,哪边黑往哪边转

缺点
红黑树的缺点是每个叶子节点只能有2个子节点,查询的时候会造成IO次数太多,同时树的层级会非常高

红黑树和AVL树的区别

  • 红黑树不是完全平衡,不会像AVL那样要求左右2边节点的 绝对值差不大于1,它只要求部分达到平衡,但是提出了为节点增加颜色,红黑是用非严格的平衡来换取增删节点时候旋转次数的降低,任何不平衡都会在三次旋转之内解决。
  • AVL是完全平衡,在增加或者删除节点的时候,旋转的次数比红黑树要多。左右2边节点的 绝对值差不大于1。由于是完全平衡,所有查询效率要比红黑树高
  • 复咋情况下,就是如有删除节点,树要回复平衡,红黑树的复衡效率更高,因为最多只需要旋转3次就能回复平衡,而AVL树可能会旋转多次,效率更低
  • 在实际运用中,如果搜索的次数远远大于插入和删除,那么选择AVL,因为查询效率更高,如果搜索,插入删除次数几乎差不多,应该选择红黑树,因为维护效率更高。

4.Hash

Hash实际上是散列函数,它可以帮助我们大幅提升检索数据的效率,这是因为 Hash 只需要一步就可以找到对应的取值,算法复杂度为 O(1)。Hash 算法是通过某种确定性的算法(比如 MD5、SHA1、SHA2、SHA3);

采用 Hash 进行检索效率非常高,例如查 id = 100的数据,基本上一次检索就可以找到数据,而 B+ 树需要自顶向下依次查找,多次访问节点才能找到数据,中间需要多次 I/O 操作,从效率来说 Hash 比 B+ 树更快。但是,hash 有很多缺点

缺点

  • Hash 索引不能进行范围查询,例如id > 100就无法匹配索引
  • Hash 索引不支持最左匹配原则,例如有联合索引 a_b_c_index,abc3个字段,Hash 索引在计算Hash 值的时候是将abc3个字段合并后再一起计算 Hash 值,不会针对每个索引单独计算 Hash 值。因此如果用到联合索引的一个或者几个索引时,联合索引无法匹配
  • Hash 索引不支持 ORDER BY 排序
  • 当数据量很大时,hash冲突的几率也会很是大,造成hash碰撞

5.B tree(多路平衡查找树)

上面讲到的树有个共同的缺点,就是每个叶子节点只能有2个子节点,这样的话都会造成树的层级太高,IO效率太低。

B-tree 利用了磁盘块的特性进行构建的树。每个磁盘块一个节点,每个节点包含了很关键字。把树的节点关键字增多后树的层级比原来的二叉树少了,这样就变成了N叉树,并且每个节点保存key和value和data,这样的存储方式的好处就是只要查询到对应数据的键值,就直接返回data,大大提高了查询效率,减少数据查找的次数和复杂度
在这里插入图片描述

缺点
这样的存储结构有个缺点,就是由于每个节点都保存了key-value-data,那么一旦这个data的数据量大的话,例如这个数据有1k,10k或者更多,那么一个磁盘块(默认16KB)就无法保存这么多节点了,因为空间是有限的,保存不了的话就会生成子节点,这样的话树的高度又增加了,磁盘IO又多了,于是B树进行优化,就有了B+树

6.B+tree

B+树和 B树最大的不同是非叶子节点只储存key和value信息,没有data,data 只保存在叶子节点上。这样做的好处是一个磁盘块可以存更多的节点,因为不需要存data了,树的高度就更矮了IO次数更低。

而且所有的叶子节点都是有序的双向链表,所有数据是按照顺序排列的,这样做的好处是范围查找,排序查找,分组查找的效率更高了,举个例子,例如查 23 < id < 52区间范围的数据,只需要找到23的这个数据,再通过有序链表,找到52,就可以快速的返回范围数据,减少了IO次数,提高查询效率
在这里插入图片描述

InnoDb的索引数据模型

在 InnoDB 中,表都是根据主键顺序以索引的形式存放的,这种存储方式的表称为索引组织表。又因为前面我们提到的,InnoDB 使用了 B+ 树索引模型,所以数据都是存储在 B+ 树中的。每一个索引在 InnoDB 里面对应一棵 B+ 树
从图中不难看出,根据叶子节点的内容,索引类型分为主键索引和非主键索引。主键索引的叶子节点存的是整行数据。在 InnoDB 里,主键索引也被称为聚簇索引(clustered index)。非主键索引的叶子节点内容是主键的值。在 InnoDB 里,非主键索引也被称为二级索引(secondary index)。

主键索引和非主键索引的查询区别

如果语句是 select * from T where ID=500,即主键查询方式,则只需要搜索 ID 这棵 B+ 树;
如果语句是 select * from T where k=5,即普通索引查询方式,则需要先搜索 k 索引树,得到 ID 的值为 500,再到 ID 索引树搜索一次。这个过程称为回表。也就是说,基于非主键索引的查询需要多扫描一棵索引树。因此,我们在应用中应该尽量使用主键查询。

索引维护

B+ 树为了维护索引有序性,在插入新值的时候需要做必要的维护;索引的每一页存放的是索引,如果新添加一个索引的话,这个索引素在的页内容满的话就需要新增一页,这时候会引起索引的移动到新的也上,影响性能
除了性能外,索引页分裂操作还影响数据页的利用率。原本放在一个页的数据,现在分到两个页中,整体空间利用率降低大约 50%。要求建表语句里一定要有自增主键。当然事无绝对,我们来分析一下哪些场景下应该使用自增主键,而哪些场景下不应该;也就是说,自增主键的插入数据模式,正符合了我们前面提到的递增插入的场景。每次插入一条新记录,都是追加操作,都不涉及到挪动其他记录,也不会触发叶子节点的分裂。而有业务逻辑的字段做主键,则往往不容易保证有序插入,这样写数据成本相对较高。除了考虑性能外,我们还可以从存储空间的角度来看。假设你的表中确实有一个唯一字段,比如字符串类型的身份证号,那应该用身份证号做主键,还是用自增字段做主键呢?由于每个非主键索引的叶子节点上都是主键的值。如果用身份证号做主键,那么每个二级索引的叶子节点占用约 20 个字节,而如果用整型做主键,则只要 4 个字节,如果是长整型(bigint)则是 8 个字节。显然,主键长度越小,普通索引的叶子节点就越小,普通索引占用的空间也就越小;所以,从性能和存储空间方面考量,自增主键往往是更合理的选择。
有没有什么场景适合用业务字段直接做主键的呢?还是有的。比如,有些业务的场景需求是这样的:**只有一个索引;该索引必须是唯一索引。你一定看出来了,这就是典型的 KV 场景。**由于没有其他索引,所以也就不用考虑其他索引的叶子节点大小的问题。这时候我们就要优先考虑上一段提到的“尽量使用主键查询”原则,直接将这个索引设置为主键,可以避免每次查询需要搜索两棵树。

7.写在最后

总结了这么多,如果你还是不明白为什么要用B+tree做存储结构,那就再反复的学习吧

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

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

相关文章

如何确认目标期刊被SCI或EI收录?

原创内容&#xff0c;仅供参考&#xff0c;欢迎大家批评指正&#xff01; 目录 通过Web of Science查询SCI期刊1. 登录Web of Science2. 查找目标期刊3. 查看期刊信息 通过Scopus查询EI期刊1. 登录Scopus2. 查找目标期刊3. 查看期刊信息 参考 通过Web of Science查询SCI期刊 1…

学习c++的第二天

目录 数据类型 基本数据类型 typedef 声明 枚举类型 类型转换 变量类型 变量定义 变量声明 左值&#xff08;Lvalues&#xff09;和右值&#xff08;Rvalues&#xff09; 变量作用域 数据类型 基本数据类型 C 为程序员提供了种类丰富的内置数据类型和用户自定义的数…

linux 中高精度timer的实现

相关结构体 每个cpu上绑定一个hrtimer_cpu_base结构体&#xff0c;它的active_bases用位记录了有哪些种类的timer&#xff0c;对应每种类型的计时器红黑树&#xff08;hrtimer_clock_base&#xff09;在hrtimer_cpu_base&#xff0d;>clock_base[]上。 软硬超时调试时机 …

相册里的视频怎么提取音频?帮你整理了几个必备的!

有的时候视频中的音频包含重要信息&#xff0c;如对话、旁白、音乐等。提取音频不仅可以节省存储空间&#xff0c;还方便对这些信息进行单独处理和利用。那么如何提取音频呢&#xff1f;下面介绍了3种方法~ 方法一&#xff1a;直接使用手机相册自带功能 1、打开手机相册&#…

PAT 乙级1090危险品装箱

题目&#xff1a; 集装箱运输货物时&#xff0c;我们必须特别小心&#xff0c;不能把不相容的货物装在一只箱子里。比如氧化剂绝对不能跟易燃液体同箱&#xff0c;否则很容易造成爆炸。 本题给定一张不相容物品的清单&#xff0c;需要你检查每一张集装箱货品清单&#xff0c;…

C++(20):explicit(true/false)

explicit通常用于声明是否运行隐式转换&#xff1a; struct A {explicit A(int) { } };int main() {A a1 10; //编译报错&#xff0c;不运行隐式的通过int构造AA a2(10); //可以显示的构造return 0; } C20扩展了explicit&#xff0c;可以通过explicit(false)来禁用&a…

selenium自动升级115以上版本谷歌游览器驱动方案

原本selenium4已经更新了自动获取驱动的方案&#xff0c;但目前最大只能获取到115版本&#xff0c;而115版本还能够使用也只是因为114版本能够驱动谷歌游览器。 如今&#xff0c;我的谷歌游览器已经到了119版本&#xff0c;以前编写的自动更新驱动的方案全部报废。 自动更新Sel…

C语言重点突破(五) 动态内存管理

前言 动态内存管理是指在一个程序运行期间动态地分配、释放和管理内存空间的过程。在应用程序中&#xff0c;当程序需要使用变量或对象时&#xff0c;需要在内存中分配一段空间&#xff0c;并在使用完毕后释放该空间&#xff0c;以提高程序的效率和性能。本文意在介绍常用动态…

PostGreSQL:JSON|JSONB数据类型

JSON JSON 指的是 JavaScript 对象表示法&#xff08;JavaScript Object Notation&#xff09;JSON 是轻量级的文本数据交换格式JSON 独立于语言&#xff1a;JSON 使用 Javascript语法来描述数据对象&#xff0c;但是 JSON 仍然独立于语言和平台。JSON 解析器和 JSON 库支持许…

Android WMS——WMS窗口添加(十)

Android 的 WMS&#xff08;Window Manager Service&#xff09;是一个关键组件&#xff0c;负责管理窗口的创建、显示、布局和交互等。Window 的操作有两大部分&#xff0c;一部分是 WindowManager 来处理&#xff0c;一部分是 WMS 来处理&#xff0c;如下图所示&#xff1a; …

Android渲染流程

目录 缓冲区的不同生命周期代表当前缓冲区的状态&#xff1a; 多个源 ViewRootImpl&#xff1a; Android4.0&#xff1a; Android5.0&#xff1a; Android应用程序调用SurfaceFliger将测量&#xff0c;布局&#xff0c;绘制好的Surface借助GPU渲染显示到屏幕上。 一个Acti…

Python中字符串前“b”,“r”,“u”,“f”,“l”的作用

文章目录 1、字符串前加 u2、字符串前加 r3、字符串前加 b4、字符串前加 f5、字符串前加 “l” 1、字符串前加 u 例&#xff1a;u"我是含有中文字符组成的字符串。" name "中文字符".replace(u"中"," ")作用&#xff1a; 前缀u表示…

webpack、rollup、parcel 优势和劣势?

结论先行&#xff1a; webpack 是模块化构建工具&#xff0c;具有强大的 loader 和插件生态&#xff0c;适用于大型复杂项目的构建&#xff1b; rollup 适用于基础库的打包&#xff0c;功能没有webpack 强大&#xff1b; parcel 适用于简单的实验性项目&#xff0c;在公司真…

搜维尔科技:Varjo在心理学、医学研究、技术、工程学等领域都在使用

该软件用于心理学、医学研究、可用性、品牌和营销等领域。vajio头显组合到了运动8.0平台中,提供了在高保真虚拟环境中进行的行为研究,否则这些环境的成本太高,不切实际,甚至无法在现实世界中再现。 在心理学、医学研究、可用性、技术、工程学、市场营销等领域工作的学术和商业研…

【编程语言发展史】C语言的诞生及其影响

目录 一、C语言的历史背景 二、C语言的设计思想 三、C语言的语法特点 四、C语言的应用领域 五、C语言的影响 六、总结 C语言是一种高级计算机编程语言&#xff0c;它的诞生和发展对计算机科学和软件工程领域产生了深远的影响。本文将详细介绍C语言的诞生及其影响&#xf…

分类预测 | Matlab实现KOA-CNN-GRU-selfAttention多特征分类预测(自注意力机制)

分类预测 | Matlab实现KOA-CNN-GRU-selfAttention多特征分类预测&#xff08;自注意力机制&#xff09; 目录 分类预测 | Matlab实现KOA-CNN-GRU-selfAttention多特征分类预测&#xff08;自注意力机制&#xff09;分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matla…

springboot源码阅读需要提前了解的知识点

SpringBoot 源码透彻解析——必须提前了解的几个知识点&#xff08;这些玩意充斥到springboot源码的各个角落&#xff09; SpringFactoriesLoader.loadFactories(ApplicationContextFactory.class,getClass().getClassLoader() : 根据 spring.factories文件&#xff0c;获取实现…

线代学习笔记-向量

numpy广播机制&#xff0c;自动增加维数 numpy中的array函数生成向量&#xff0c;&#xff08;&#xff09;是函数标配&#xff0c;&#xff08;&#xff09;下必有一个[]表示向量元素集合&#xff0c;第一层[]下的后每一个[]代表一行&#xff0c;没有这个[]&#xff0c;表示这…

AI图像识别初次尝试

1.人形识别结果 2.代码 pythonOpenCVyolov3训练库&#xff0c;代码如下&#xff1a; #!/usr/bin/env python3 # -*- coding: utf-8 -*- import cv2 import numpy as np import osimgFiles["pic03.jpg", "pic04.jpg"]netNone classesNone colorsNonedef r…

Python小试牛刀:GUI(图形界面)实现计算器UI界面(二)

上一篇&#xff1a;Python小试牛刀&#xff1a;GUI&#xff08;图形界面&#xff09;实现计算器UI界面&#xff08;一&#xff09;-CSDN博客 在上一篇文章中介绍了Python GUI常用的库&#xff0c;以及运用GUI标准库tkinter仅设计了计算器的UI界面。 而在本篇文章&#xff0c;…