从 Hash索引、二叉树、B-Tree 与 B+Tree 对比看索引结构选择

从 Hash索引、二叉树、B-Tree 与 B+Tree 对比看索引结构选择

  • 1、Hash 结构
    • 1.1、关于 Hash 数据结构
    • 1.2、InnoDB索引为啥不选 Hash 结构
    • 1.3、关于InnoDB 提供自适应 Hash 索引 (Adaptive Hash Index)
  • 2、二叉搜索树
  • 3、平衡二叉树(AVL树 )
  • 4、B-Tree(B树)
  • 5、B+Tree (B+树)
    • 5.1、B+Tree 结构
    • 5.2、B+Tree 相关思考题

       数据结构可以说是程序员常用,但大部分人不知其所以然的知识点,本文将对Hash、二叉搜索树、平衡二叉树、B-Tree、B+Tree几种数据做一下梳理和总结。
 

1、Hash 结构

 

1.1、关于 Hash 数据结构

 
Hash 本身是一个函数,又被称为散列函数,可以大幅提升检索数据的效率。

  • Hash 算法是通过某种特定性的算法(比如:MD5、SHA1、SHA2、SHA3)将输入转变为输出。相同的输入永远可以得到相同的输出,假设输入内容有微小偏差,在输出中通常会有不同的结果。

  • Hash值的长度是固定的,而输入数据的可能性是无限的,这就会出现不同的输入数据映射到了相同的Hash值,这种现象就叫Hash碰撞

  • 解决Hash碰撞的常见方案有开放寻址法和链表法。开放寻址法是在发生碰撞时,尝试寻找下一个可用的槽位来存储数据。链表法则是将映射到同一个Hash值的数据存储在一个链表中,通过链表来解决碰撞问题

  • 当链表长度过长时,查询效率会降低,此时可以将链表转换为红黑树来提高查询效率。红黑树是一种自平衡的二叉查找树,能够保证最坏情况下的查询时间复杂度为O(log n),其中n为节点数量。

在这里插入图片描述
举例:如果想要验证两个文件是否相同,可以直接对比两个文件通过Hash函数计算出的结果,如两个文件通过Hash函数计算的结果一样,即文件相同,否则不同。

 
提高查询速度的数据结构,常见的有两类:

  • 树,例如:平衡二叉树,查询、插入、修改、删除的平均时间复杂度都是O(log2N) .
  • 哈希,例如:HashMap,查询、插入、修改、删除的平均时间复杂度都是O(1) ;(key,value)

采用 Hash 进行检索效率非常高,基本都是一次检索就能找到数据,B+Tree 需要自顶向下依次查找,多次访问节点才能找到数据,中间需要多次 I/O 操作,从效率上来将 Hash 比 B+Tree 更快

Hash 索引适用的存储引擎如表所示:

索引/存储引擎InnoDBMyISAMMemory
Hash 索引不支持不支持支持

Hash 索引的使用场景:

  • ① 当字段的重复度低,且经常需要进行等值查询时,采用 Hash 索引是个不错的选择。

  • ② Redis 存储的核心就是 Hash 表。

  • ③ InnoDB 提供自适应 Hash 索引 (Adaptive Hash Index)
     

1.2、InnoDB索引为啥不选 Hash 结构

 
Hash结构效率高,那为啥InnoDB的索引结构要设计成树型呢?

  • 原因①,Hash索引仅能满足 (=)(<>)和 in 查询。如果进行 范围查询,时间复杂度会退化为O(n),树型结构的有序特性,依然能保持 O(log2N) 的高效率。
  • 原因②,Hash索引有一个缺陷,数据的存储是没有顺序的,在 ORDER BY 的情况下,使用 Hash 索引还需要对数据重新排序。
  • 原因③,对于联合索引而言,Hash值是将联合索引键合并后一起来计算,无法对单独的一个键或几个索引键进行查询。
  • 原因④,对于等值查询而言,通常 Hash 索引的效率更高,但如果索引列的重复值很多,效率就会降低。因为当遇到 Hash 冲突时,需要遍历桶中的行指针来进行比较,找到查询的关键字,非常耗时。故 Hash 索引常不会用到重复值多的列上,比如 性别、年龄等。

 

1.3、关于InnoDB 提供自适应 Hash 索引 (Adaptive Hash Index)

 
       如果某个数据经常被访问,当满足一定条件时,会将这个数据页的地址存放到 Hash 表中,下次查询的时候,就会直接找到这个数据页所在的位置。采用自适应 Hash 索引的目的就是,方便根据 SQL 的查询条件,加速定位到叶子节点,特别是当 B+Tree 比较深,层级比较多时,自适应Hash能显著提高数据的检索效率。

 

-- 查询是否开启 自适应Hash索引,默认为 ON ,开启.
show variables like '%adaptive_hash_index%';

在这里插入图片描述

 

2、二叉搜索树

 
如果我们利用二叉树作为索引结构,那么磁盘的IO次数和索引树的高度是相关的。

二叉搜索树(二叉查找树)的特点

  • 一个节点只能有两个子节点,也就是一个节点度不能超过2.
  • 左子节点 < 本节点;右子节点 >= 本节点,比我大的向右,比我小的向左

 

二叉搜索树的查找规则:

二叉搜索树(Binary Search Tree),搜索某个节点和插入节点的规则一样,假设搜索插入的数值为key:

  • ① 如果 key 大于根节点,则在右子树中进行查找;
  • ② 如果 key 小于根节点,则在左子树中进行查找;
  • ③ 如果 key 等于根节点,也就是找到了这个节点,返回根节点即可。

在这里插入图片描述
二叉查找树可能退化成一条链表,查找数据的时间复杂度为O(N),如下图:
在这里插入图片描述

 

3、平衡二叉树(AVL树 )

 
       为解决二叉搜索树可能退化成链表的问题,就出现了平衡二叉树(Balanced Binary Tree),又称为 AVL 树(有别于 AVL 算法),它是在二叉搜索树的基础上增加了一些约束:平衡二叉树是一课空树,或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一颗平衡二叉树

       常见的平衡二叉树包含:平衡二叉搜索树红黑树数堆伸展树一般平衡二叉树指的就是平衡二叉搜索树,搜索的时间复杂度为O(log2n),数据查询的时间主要依赖于磁盘的 I/O次数,当n 越大,查询越复杂。

在这里插入图片描述

       每访问一次节点就需要进行一次磁盘I/O操作,以上图示例来讲,需要进行4次I/O操作。虽然平衡二叉树的效率高,但是树的深度比较高时,也意味着磁盘I/O操作次数多,就会影响整体数据查询的效率。

 

4、B-Tree(B树)

 
       B树(Balance Tree)也就是多路平衡查找树,简写为 B-Tree(这里的横杠是连接符,而不是减号)。B-Tree 的高度远小于平衡二叉树的高度。B-Tree 关键点如下:

  • B-Tree 在插入、删除节点的时候,如果导致树不平衡,就通过自动调节节点的位置来保持树的自平衡

  • 关键字集合分布在整棵树中,如果一个磁块包括了x个关键字,那指针数为x+1,叶子节点和非叶子节点都存放数据。搜索有可能在非叶子节点结束。

  • 搜索性能等价于在关键字全集内做一次二分查找。

  • 对于一个M阶(每个节点最多可以包括M个子节点)的B-Tree,根节点的儿子数的范围是[2,M],且所有叶子节点位于同一层。

    在这里插入图片描述

假设查询关键字为 8 的数据。

  • ① 与根节点的关键字26 和 36 比较,8 小于26 ,取磁块1的P1指针向下级节点查找。
  • ② 按磁块1的P1指针找到磁块2,比对关键字 6 和 21,8大于6且小于21,取取磁块2的P2指针向下级节点查找。
  • ③ 按磁块2的P2指针找到磁块6,对比磁块6的关键字8和18,找到关键字8.

       在B-Tree 的搜索中,是把数据读取出来,然后在内存中进行比较,那比较的时间可忽略不计。读取磁盘块本身需要进行I/O操作,其消耗的时间比在内存中进行比较需要的时间较多,是数据查找用时的重要因素。B-Tree相比于平衡二叉树来说,磁盘I/O操作要少效率高,只要树的高度足够低,I/O次数足够少,就可以提高查询性能

 

5、B+Tree (B+树)

 

5.1、B+Tree 结构

 
       B+Tree 是一种多路搜素树,基于B-Tree做出了改进。主流的 DBMS都支持 B+Tree 的索引方式。B+Tree相比于B-Tree在查询效率、磁盘读写性能和范围查询方面更具优势,B+Tree 比 B-Tree 更适合文件索引系统
 
在这里插入图片描述

B+Tree和B-Tree的区别主要体现在以下三个方面:

  • 内部节点存储数据的方式:B-Tree的每个内部节点都存储数据,而B+Tree的内部节点并不存储数据,只作为索引使用,数据都存储在叶子节点上。因为B+Tree只在叶子节点存储数据,所以在查询时稳定性更好,且查询速度更快。

  • 叶子节点的链接方式:B+Tree的叶子节点之间通过指针连接,形成一个有序链表,便于进行范围查询。而B-Tree的叶子节点并没有相连,B-Tree 做范围查询时,需要通过中序遍历才能实现。在范围查询上,B+Tree 的效率比 B-Tree 高。

  • 磁盘读写性能:B+Tree相比于B-Tree,在磁盘读写性能上更有优势。这是因为B+Tree的内部节点并没有指向关键字具体信息的指针,所以其内部节点相对B-Tree更小,如果把内部节点和叶子节点存放在同一块磁盘内,那么盘块容纳的节点数目比B-Tree更多,一次性读入内存中的需要查找的关键字也就越多,相对来说IO读写次数也就降低了。
     

5.2、B+Tree 相关思考题

 
1、为了减少IO,B+Tree 索引树会一次性加载吗?

  • ① 数据库索引存储在磁盘上,如果数据量过大,必然会导致索引的大小也会很大,超过几个G.
  • ② 当利用索引查询时,是不可能将全部几个G 的索引数据,全都加载到内存中的。只能逐一加载每个磁盘页,因此磁盘页对应着索引树的节点。

 
2、B+Tree 的存储能力如何?为何说一般查找行记录,最多只需要 1~3次磁盘IO ?

InnoDB 存储引擎中数据页的大小默认为 16KB,一般表的主键类型为 int(占4个字节)或 bigint(占8个字节),指针类型一般也为4或8个字节,所以一个根节点或内节点的数据页(B+Tree中的一个节点)中大概存储 16KB/(8B+8B) = 1K 个键值。估算一下,就当K 的取值为10^3,那一个深度为3 的B+Tree 索引可以维护的数据为 10^3 * 10^3 * 10^2 = 1亿 条记录(这里假设一个叶子节点的数据页可以存 100 条行记录数据)。

实际情况中每个节点可能不会填充满,所以在数据库中,B+Tree 的高度一般都在 2~4 层。MySQL 的 InnoDB 存储引擎在设计时,将根节点常驻内存,也就是说查找某一键值的行记录时,最多只需要1~3次磁盘 IO 操作。

 
3、为什么说B+Tree 比 B-Tree 更适合实际应用中,操作系统的文件索引和数据库索引?

  • B+Tree 的磁盘读写代价更低

B+Tree 的内部节点,并没有指向关键字具体信息的指针,故其内部节点相对B-Tree 更小。通俗来说,就是B-Tree每个层级的节点都存放的行数据,但是B+Tree 只有在叶子节点存放行数据,内节点存放主键或非聚簇索引字段,所以一般情况来讲相同的数据体量,B+Tree的层级会低,磁盘IO操作次数更少,磁盘读写代价更低。

  • B+Tree 的查询效率更稳定

B+Tree 的叶子节点才会有用户记录行数据,所以任何关键字的查找,必须走一条从根节点到叶子节点的路,所有关键字查询的路径长度相同,导致每一个数据的查询效率相当。

 
4、Hash 索引和 B+Tree 索引的区别?

  • ① Hash 索引不能进行范围查询,B+Tree 可以。

  • ② Hash 索引不支持联合索引的最左原则(即联合索引的部分索引无法使用),B+Tree 可以。

  • ③ Hash 索引不支持 ORDER BY 排序,B+Tree 可以(B+Tree索引数据是有序的)。

  • ④ Hash 索引不支持模糊查询,B+Tree 使用LIKE进行模糊查询时, LIKE 后面后模糊查询(比如%结尾)可以起到优化作用。

  • ⑤ InnoDB 不支持哈希索引,但提供自适应 Hash 索引 (Adaptive Hash Index)。

 

5、Hash 索引和 B+Tree 索引是在键索引时,手动指定的吗?

对于MySQL而言,针对 InnoDB 和 MyISAM 存储引擎,都会默认采用 B+Tree 索引,无法使用 Hash 索引。InnoDB 提供的自适应 Hash 是不需要手动指定的。如果 Memory/Heap 和 NDB 存储引擎,是可以进行选择 Hash 索引的。

 

 
 
 
 
 
 
 
.

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

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

相关文章

莫名其妙el-table不显示问题

完全复制element-ui中table代码&#xff0c;发现表格仍然不显示&#xff0c;看别人都说让降低版本&#xff0c;可我不想降低啊&#xff0c;不然其他组件有可能用不了&#xff0c;后来发现可以通过配置vite.config.js alias: {: path.resolve(__dirname, src),vue: vue/dist/vue…

<蓝桥杯软件赛>零基础备赛20周--第3周

报名明年4月蓝桥杯软件赛的同学们&#xff0c;如果你是大一零基础&#xff0c;目前懵懂中&#xff0c;不知该怎么办&#xff0c;可以看看本博客系列&#xff1a;备赛20周合集 20周的完整安排请点击&#xff1a;20周计划 每周发1个博客&#xff0c;共20周&#xff08;读者可以按…

【脚本笔记】AssetDatabase

AssetDatabase是编辑器下的处理资源操作的重要类&#xff0c;主要用于访问资源并针对资源执行操作的接口。 这里面所有的操作路径都是基于Unity项目的相对路径也就是Assets/xxx或者Assets/xxx.jpg这种。CacheServer 主要解决的是缩短大型团队导入资源的时间。当配置后&#xff…

V90伺服调试软件使用介绍(SINAMICS V-ASSISTANT Commissioning tool)

V90伺服驱动器调试软件SINAMICS V-ASSISTANT Commissioning tool下载地址如下: 西门子官网 选型|资料https://www.ad.siemens.com.cn/productportal/prods/sinamics%20v90/00_selectionziliao.htmlCSDN网址 https://download.csdn.net/download/m0_46143730/88485182

【并发编程】进程与线程

主要知识点&#xff1a; 进程和线程的概念 并行和并发的概念 线程基本应用 一、进程与线程 进程 程序由指令和数据组成&#xff0c;但这些指令要运行&#xff0c;数据要读写&#xff0c;就必须将指令加载至 CPU&#xff0c;数据加载至内存。在指令运行过程中还需要用到磁盘、…

element-plus DateTimePicker日期选择器,限制指定日期和时间不可选择

element-plus日期选择器&#xff0c;在指定日期时间前不可选择。 限制日期选择&#xff0c;使用disabled-date 限制小时选择&#xff0c;使用disabled-hours 限制分钟选择&#xff0c;使用disabled-minutes 限制毫秒选择&#xff0c;使用disabled-seconds 指定日期当天的时间有…

ECCV 22丨BUTD-DETR:图像和点云的语言标定Transformer

来源&#xff1a;投稿 作者&#xff1a;橡皮 编辑&#xff1a;学姐 论文链接&#xff1a;https://arxiv.org/abs/2112.08879[1] 主页链接&#xff1a;https://github.com/nickgkan/butd\_detr[2] 摘要&#xff1a; 在二维和三维场景中&#xff0c;大多数模型的任务都是将指涉…

GoLand GC(垃圾回收机制)简介及调优

GC(Garbage Collector)垃圾回收机制及调优 简单理解GC机制 其实gc机制特别容易理解&#xff0c;就是物理内存的自动清理工。我们可以把内存想象成一个房间&#xff0c;程序运行时会在这个房间里存放各种东西&#xff0c;但有时候我们会忘记把不再需要的东西拿出去&#xff0c…

Windows下Redis配置密码,并设置自启动

1. 解压redis修改配置文件&#xff08;设置密码&#xff09; 打开Redis的配置文件&#xff0c;通常位于Redis安装目录下的 redis.windows.conf 去掉"requirepass"前注释&#xff0c;修改"foobared"为要设置的密码 requirepass foobared2.注册服务&#x…

Mybatis-Plus通用枚举功能 [MyBatis-Plus系列] - 第493篇

历史文章&#xff08;文章累计490&#xff09; 《国内最全的Spring Boot系列之一》 《国内最全的Spring Boot系列之二》 《国内最全的Spring Boot系列之三》 《国内最全的Spring Boot系列之四》 《国内最全的Spring Boot系列之五》 《国内最全的Spring Boot系列之六》 S…

JAVA数据类型和变量

一、字面常量 常量即程序运行期间&#xff0c;固定不变,不可修改的量称为常量。 public class Demo{public static void main(String[] args){System.Out.println("hello world!");System.Out.println(100);System.Out.println(3.14);System.Out.println(A);System…

Linux--进程替换

1.什么是进程替换 在fork函数之后&#xff0c;父子进程各自执行代码的一部分&#xff0c;但是如果子进程想要执行一份全新的程序呢&#xff1f; 通过进程替换来完成&#xff0c;进程替换就是父子进程代码发生写时拷贝&#xff0c;子进程执行自己的功能。 程序替换就是通过特定的…

maven环境变量,安装源,本地仓库配置

1. maven环境变量 我这里用的是idea自带的maven 数值为&#xff1a; D:\software\computer_software\java\IDEAJ\IDEAJ2021.2.1\IntelliJ IDEA 2021.2.1\plugins\maven\lib\maven3\bin 2. 安装源更换为阿里云&#xff08;我不知道清华源是什么网址&#xff0c;网上也没查到&am…

目标检测算法发展史

前言 比起图像识别&#xff0c;现在图片生成技术要更加具有吸引力&#xff0c;但是要步入AIGC技术领域&#xff0c;首先不推荐一上来就接触那些已经成熟闭源的包装好了再提供给你的接口网站&#xff0c;会使用别人的模型生成一些图片就能叫自己会AIGC了吗&#xff1f;那样真正…

Linux学习第25天:Linux 阻塞和非阻塞 IO 实验(二): 挂起

Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 为方便和上一节的衔接&#xff0c;在正式开始学习前&#xff0c;先把本节的思维导图引入&#xff1a; 二、阻塞IO实验 1.硬件原理图分析 2.实验程序 #define I…

【排序算法】 归并排序详解!分治思想!

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; 算法—排序篇 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言&#x1f324;️归并排序的思想☁️基本思想☁️归并的思想实现☁️分治法 &#x1f3…

国产芯片vs“国际水平”,有距离也有超越!

当前&#xff0c;国产芯片正在迎来全新的发展阶段。国产终端芯片性能怎么样&#xff0c;与国际主流产品相比&#xff0c;表现如何&#xff1f;今天笔者就针对目前热度较高的四款国产CPU进行参数分析与性能跑分横向对比。 此次国产芯片评测型号分别是海光C86-3250、龙芯3A5000H…

Python 读取 Word 详解(python-docx)

文章目录 1 概述1.1 第三方库&#xff1a;python-docx 2 新建文档2.1 空白文档2.2 标题2.3 段落2.4 文本2.5 字体2.6 图片2.7 表格 3 扩展3.1 修改文档3.2 读取文档 1 概述 1.1 第三方库&#xff1a;python-docx > pip install python-docx2 新建文档 2.1 空白文档 impo…

idea中Run/Debug Python项目报错 Argument for @NotNull parameter ‘module‘ of ...

idea中Run/Debug Python项目报错 Argument for NotNull parameter module of ... idea中运行Python项目main.py时报错&#xff1a; Error running main: Argument for NotNull parameter module of com/intellij/openapi/roots/ModuleRootManager.getInstance must not be nu…