Mysql索引为啥用B+树

项目中一直使用Mysql,对于慢sql优化也一直在做,但是一直没有梳理清楚,这里简单总结一下

首先看一下mysql为什么要使用索引

1)索引是帮助Mysql高效获取数据的 排好序的 数据结构

2)索引存储在文件里

首先说明一下,Mysql是使用B+树作为索引的

在没有索引的情况下,如果要找到一条记录的化,是通过全表扫描的

一张数据表中记录了分数,有两个字段,id,core:

如果要查找core=5 的记录,where core=5 ,按照全表扫描顺序查找从第一条记录开始,需要查询6次才可以找到

如果我们对core字段加上索引后,假设使用的是最简单的二叉树作为索引的存储方式,同样的如果查找 where core =5 的记录,按照二叉树的存储结构,如下图

那么我们查找3次就可以找到了

那为什么Mysql中不使用二叉树作为索引呢,那就来看看二叉树的特点

(一)二叉树

二叉树是一种比顺序结构更加高效的查找目标元素的结构,从父节点开始,和目标元素比较,如果相等返回当前节点,如果目标元素值小于当前节点,则移动到当前节点的左侧子节点比较,如果目标元素值大于当前节点,则移动到当前节点的右侧子节点比较,反复操作,最终找到目标元素节点的位置后返回,二叉树的查找时间复杂度可以达到O(log2(n))。

但是二叉树有一个致命的缺点,如果我们的目标元素是有规律递增或者递减的,这样出来的二叉树就会失去平衡,变成了一个线性链表结构,比如使用二叉树作为索引,那么我们将数据库主键ID这一列建立索引,得到的索引的数据结构就变成下面这样,这种情况下,查找数据和没有索引是一样的效果,那么索引就起不到作用了。

针对上面的这种场景,我们很容易想到那为什么不用可以保持平衡的二叉树呢,比如说红黑树,那么我们就来看看红黑树的特点

(二)红黑树

红黑树是一种平衡二叉树,它继承了二叉树的优点,由解决了二叉树遇到的自增数据索引失效的问题,因为红黑树的会对树的结构进行调整,进行左旋或者右旋及颜色变换等操作,始终保证 左子节点数<父节点数<右子节点数

红黑树不作为Mysql索引的原因是,当数据量大 时候,树的深度也很大,每个父节点最多只能有两个子节点,如果表中有很多数据,那么树的深度很大,达到十几或几十层,后续会了解到这样的深度对于Mysql的磁盘寻址非常不利,也是相当耗时的。

那问题来了,如果是因为树的深度太高,查找数据不方便,那为什么不用可以直接定位到某条数据的hash算法作为Mysql的索引呢,那么我们来看看Hash的特点

(三)Hash算法

对数据进行hash,也就是散列运算,然后将hash结果作为文件指针,可以从索引文件中获得数据的文件指针,再到数据文件中获取到数据,按照这种结构,我们很快能定位出来某一条数据的位置,查询的效率非常高,那么它的问题点在哪呢,那就是不支持范围查询,分页或者大于 小于某个范围的查询都是无法支持的,只能支持固定的 字段名 = 目标值的场景,同样也不适合Like这种模糊查询,所以这种算法肯定是不适合作为数据库的索引的。

那我们再来看看平衡二叉树的问题

平衡二叉树的要求是 节点的子节点高度差不能超过1,如上图中节点20,左节点高度为1,右节点高度为0,高度差为1,所以上图可以定义为一个平衡二叉树,保证二叉树平衡的方法就是通过左旋或者右旋等操作

上图中保存的id的索引,如果要查找id=8的数据,首先要把根节点加载到内存中,然后进行比较,8比根结点的10小,所以要加载10的左节点就是5对应的磁盘块2,把5加载到内存中进行比较,8和5比较,需要加载5的右节点也就是8的索引对应的数据,发现命中,整个过程中进行了3次IO。

那么现在来看看怎么找到索引对应的数据呢

索引保存数据的方式一般有两种,第一种是在节点的数据区保存ID=8的行数据的所有数据具体内容,另一种方式是在节点的数据区保存的是真正保存数据的磁盘地址。

平衡二叉树解决了线性链表的问题,查询效率也还可以,但是Mysql不选用这种结构作为索引的原因总结一下:

1)搜索效率不足,在树的结构中,树的深度决定了搜索的IO次数,上面的查找id=8的数据,就进行了3次IO,当数据量达到百万级别的时候,树的高度导致的IO次数就很恐怖了。

2)查询的效率不稳定,如果查找的数据正好落在根节点,那么只需要一次IO,如果是在叶子节点,那么就需要多次IO。

3)节点存储的数据内容太少,没有很好的利用操作系统和磁盘数据交换特性,也没有很好的利用磁盘IO的预读能力。操作系统和磁盘之间一次数据交换是以页为单位的,一页 = 4K,也就是每次IO交互操作系统会将4K的数据加载到内存中,但是在二叉树的每个节点的结构中只保存了一个关键字,一个数据区,两个子节点的引用,并不能够填满4K的数据量,也就是辛辛苦苦做了一次IO操作,却只加载了一个关键字,在数的高度很高,搜索的数据又是在叶子节点,取一个关键字需要做很多次的IO

有没有办法解决这种问题呢?

有的,一种多路平衡查找树(Balance Tree),B Tree是一个绝对平衡树,所有的叶子节点在同一个高度

看一下定义,上面的这个树是一个 2-3树(每个节点存储2个关键字,有3路),每个节点保存的关键字个数和路数关系为:关键字个数=路数-1

假设从上图中查找id=28的数据,B Tree的查找过程是:首先把根结点加载到内存中,加载了17和35两个关键字, 比较,如果X<17,则指向P1,如果X=17,命中返回,如果 17<X<35,则指向P2,如果X=35,则命中返回,如果X>35,则指向P3,按照如上规则,命中28后,就去加载28对应的数据,找到28对应 数据区,数据区中存储的是具体的数据或者是指向数据的指针。

这种数据结构能够很好的利用操作系统和磁盘的交互特性,Mysql为了能更好的利用磁盘的预读能力,将页的大小设置为16K,就是将一个节点(磁盘块)的大小设置为16K,一次IO将一个节点(16K)内容加载到内存中,假设关键字的类型是int,4个字节,每个关键字对应的数据区也为4个字节,不考虑子节点应用的情况下,上图中每个节点大约能够存储(16*1000)/8 = 2000个关键字,那么对应的就是2001个路数,对于这种有2001个路数的B树,三层的高度能够搜索到的关键字的个数是远远大于普通的二叉树的

在B树保持树的平衡的过程中,每次关键字的变化都会导致机构发生很大的变化,这个过程是特别浪费时间的,所以创建索引一定要创建合适的索引,而不是把所有的字段都建立索引,创建冗余的索引只会对数据的增加、删除、修改增加更大的性能消耗。

既然B树已经能很好的解决问题了,为什么还需要用B+树呢?

首先来看一下B+树的概念

B+树是B树的一个变种,它不再遵循 关键字个数=路数-1 这个规则,数据的检索规则是采用的左闭合取件,路数和关键字的个数关系为1:1,看下图:

如果查找id=1的数据,搜索的规则是 1<= X <28 ,找到P1, 28<=X <66 ,找到P2, 66<=X,找到P3,最终是在叶子节点 节点1的数据区中获取真正的数据。

总结一下B树和B+树的区别:

1、B+树的关键字的搜索采用的是左闭合区间,之所以要这样是因为要最好的去支持自增的id,也是Mqsql设计的初衷,保证id=1命中的情况下,也去继续往下查找,知道找到叶子节点中1

2、B+树中的根结点和支节点中没有数据区,关键字对应的数据只保存在叶子节点中,所以只有叶子节点中的关键字数据区才会保存真正的数据内容或者数据对应的地址,但是在B树中,如果根结点命中,是直接返回的,B+树中,叶子节点不会保存子节点的引用

3、B+树的叶子节点是顺序排列的,并且相邻节点之间是顺序引用的关系,叶子节点之间通过指针相连

Mysql为什么最终选择了B+树作为索引的数据结构

1.B树能解决的问题,B+树都能解决,且能够更好的解决,降低了树的高度,增加节点的数据存储量。

2.B+树的扫库和扫表能力更强,如果根据索引去根据数据表扫描,对B树扫描,需要整颗树遍历,B+树只需要遍历所有的叶子节点

3.B+树的磁盘读写能力更强,根结点和支节点不保存数据区,所有的根结点和支节点天同样大小的情况下,保存的关键字更多,叶子结点不存子节点的引用,所以,B+树读写一次磁盘加载的关键字更多

4.B+树具有天然的排序功能

5.B+树的查询效率更加稳定,每次查询数据,查询IO次数是稳定的。

原文地址:https://www.cnblogs.com/wangflower/p/12237762.html

时间: 2024-10-01 20:33:20

Mysql索引为啥用B+树的相关文章

Mysql索引为什么用B+树而不用B-树

先从数据结构的角度来看 我们知道B-树和B+树最重要的一个区别就是B+树只有叶节点存放数据,其余节点用来索引,而B-树是每个索引节点都会有Data域. 这就决定了B+树更适合用来存储外部数据,也就是所谓的磁盘数据. 从Mysql(Inoodb)的角度来看 B+树是用来充当索引的,一般来说索引非常大,尤其是关系性数据库这种数据量大的索引能达到亿级别,所以为了减少内存的占用,索引也会被存储在磁盘上.那么Mysql如何衡量查询效率呢?磁盘IO次数,B-树(B类树)的特定就是每层节点数目非常多,层数很少

B+树|MYSQL索引使用原则

MYSQL一直了解得都不多,之前写sql准备提交生产环境之前的时候,老员工帮我检查了下sql,让修改了一下存储引擎,当时我使用的是Myisam,后面改成InnoDB了.为什么要改成这样,之前都没有听过存储引擎,于是网上查了一下. 事实上使用不同的存储引擎也是有很大区别的,下面猿友们可以了解一下. 一.存储引擎的比较 注:上面提到的B树索引并没有指出是B-Tree和B+Tree索引,但是B-树和B+树的定义是有区别的. 在 MySQL 中,主要有四种类型的索引,分别为: B-Tree 索引, Ha

MySQL 索引与 B+ 树

MySQL 索引与 B+ 树 B+ 树 MySQL Innodb 存储引擎是使用 B+ 树来组织索引的.在介绍 B+ 树以前,先认识一下什么是 B 树,B 树是平衡二叉树,与一般的二叉查找树不同,平衡二叉树首先满足二叉查找树的定义(左子树的键小于根的键,右子树的键大于根的键),其次必须满足任何节点的两个子树的高度最大差为 1.B 树的维护要求插入和更新节点时,通过 1 次或多次左旋和右旋来满足平衡的条件.二叉查找树是否平衡直接影响了查找需要比较的次数. B+ 树与普通的二叉树不同,它的节点由多个

MySQL索引(二)B+树在磁盘中的存储

MySQL索引(二)B+树在磁盘中的存储 回顾 ? 上一篇文章<MySQL索引为什么要用B+树>讲了MySQL为什么选择用B+树来作为底层存储结构,提了两个知识点: B+树索引并不能直接找到行,只是找到行所在的页,通过把整页读入内存,再在内存中查找. 索引的B+树高度一般为2-4层,查找记录时最多只需要2-4次IO. 为进一步知其所以然,今天来聊聊B+树索引在物理磁盘上是怎么设计存储的. 一.理解为什么要减少磁盘IO次数 众所周知,MySQL的数据实际是存储在文件中,而磁盘IO的查找速度是要远

MySQL 索引B+树原理,以及建索引的几大原则

MySQL事实上使用不同的存储引擎也是有很大区别的,下面猿友们可以了解一下. 一.存储引擎的比较 注:上面提到的B树索引并没有指出是B-Tree和B+Tree索引,但是B-树和B+树的定义是有区别的. 在?MySQL?中,主要有四种类型的索引,分别为:B-Tree 索引, Hash 索引, Fulltext 索引和 R-Tree 索引. B-Tree?索引是?MySQL?数据库中使用最为频繁的索引类型,除了 Archive 存储引擎之外的其他所有的存储引擎都支持 B-Tree 索引.Archiv

MySQL索引-B+树(看完你就明白了)

索引是一种数据结构,用于帮助我们在大量数据中快速定位到我们想要查找的数据.索引最形象的比喻就是图书的目录了.注意这里的大量,数据量大了索引才显得有意义,如果我想要在 [1,2,3,4] 中找到 4 这个数据,直接对全数据检索也很快,没有必要费力气建索引再去查找. 索引在 MySQL 数据库中分三类: B+ 树索引 Hash 索引 全文索引 我们今天要介绍的是工作开发中最常接触到的 InnoDB 存储引擎中的 B+ 树索引.要介绍 B+ 树索引,就不得不提二叉查找树,平衡二叉树和 B 树这三种数据

MySQL中的索引为什么使用B+树实现

一.前言 ??这几天在研究MySQL相关的内容,而MySQL中比较重要的一个内容就是索引.对MySQL索引有了解的应该都知道,B+树是MySQL索引实现的一个主要的数据结构.今天这篇博客就来简单介绍一下B树.B+树以及MySQL索引使用这种数据结构实现的原因. 二.正文 2.1 B树 ??关于B树的操作细节我这里就不详细介绍了,这里主要介绍一下B树的结构,让大家对B树有一个大致的了解. ??这里首先要纠正一个问题,网上大量文章将B树称为B-(减)树,但其实这是一种错误的叫法.会这么叫是因为B树的

MySQL索引底层实现原理

优秀博文: MySQL索引背后的数据结构及算法原理 B树.B-树.B+树.B*树[转],mysql索引 MySQL 和 B 树的那些事 索引的本质 MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构.提取句子主干,就可以得到索引的本质:索引是数据结构. 我们知道,数据库查询是数据库的最主要功能之一.我们都希望查询数据的速度能尽可能的快,因此数据库系统的设计者会从查询算法的角度进行优化.最基本的查询算法当然是顺序查找(linear search),这种复杂度为O

MySQL索引那些事

原文链接 大家有没有遇到过慢查询的情况,执行一条SQL需要几秒,甚至十几.几十秒的时间,这时候DBA就会建议你去把查询的 SQL 优化一下,怎么优化?你能想到的就是加索引吧? 为什么加索引就查的快了?这就要从索引的本质以及他的底层原理说起. 索引是什么 那索引到底是什么呢?你是不是还停留在大学学『数据库原理』时老师讲的“索引就像字典的目录”这样的概念?老师讲的没错,但没有深入去讲. 其实索引就是一种用于快速查找数据的数据结构,是帮助MySQL高效获取数据的排好序的数据结构. 索引的好处 举例说明