一、前言

为了讲清楚这个问题,我们要先了解什么是索引。

我记得刚刚学习数据库的时候,老师喜欢用书本的目录来类比数据库的索引,并告诉我们索引能够像目录一样,让我们更快地找到想要找到的数据。

如果是第一次接触索引,这个比喻能够让我们有一个直观的印象。但是当深入去学习索引的时候,我们不能继续持有索引即目录的思想,我们要跳出来去思考索引的本质是什么。

二、索引的本质

在没有索引的情况下,我们查找数据只能按照从头到尾的顺序逐行查找,每查找一行数据,意味着我们要到到磁盘相应的位置去读取一条数据。

如果把查询一条数据分为到磁盘中查询和比对查询条件两步的话,到磁盘中查询的时间会远远大于比对查询条件的时间,这意味着在一次查询中,磁盘io占用了大部分的时间。更进一步地说,一次查询的效率取绝于磁盘io的次数,如果我们能够在一次查询中尽可能地降低磁盘io的次数,那么我们就能加快查询的速度。

在知道了减少磁盘io能加快查询速度后,我们就要聚焦于如何减少磁盘io。如果按照原表逐行查询的话,n条数据就要查询n次,也就是O(N)的时间复杂度,为了减少磁盘io的次数,我们必须用一种查询时间复杂度更低的数据结构来保存数据。

这种查询时间复杂度低的数据结构,我们称之为索引。所以通俗来说,索引其实就是某种数据结构,能充当索引的数据结构是多种多样的。

三、索引的选择

既然索引是一种便于查询的数据结构,如果大家对数据结构有一定了解的话,大概率会首选树型结构。毕竟树型结构普遍有着O(logN)的查询时间复杂度,而且插入删除数据的性能也比较平均。(可能你会说数组,哈希表的查询速度也很高啊,这个后面也会分析)

虽然我们都已经知道Mysql中最常用的引擎像InnoDB和MyISAM,最终都选择了B+树作为索引,但是这里我还是打算从最常见的二叉树开始讲起,推导一下为什么最终选择了B+树作为索引,并比较一下几种树型结构在充当索引时的优劣。

二叉树

最普通的二叉树的问题在于他不能保证O(logN)的查询时间复杂度,我们看下面的图:

由于插入的元素逐渐增大,元素始终在右边进行插入,好好的一棵二叉树最终变成了一条“链表”。在这种极端的情况下,二叉树的查询时间复杂度不再是O(logN),而是退化为O(N),这样显然不符合索引的要求。

平衡二叉树(红黑树)

像红黑树这样的平衡二叉树,无论如何插入元素,他都可以通过一些旋转的方法调整树的高度,使得整棵树的查询效率维持在O(logN),如下图所示:

这么来说他已经符合了成为索引的必备条件,但是最终没有选择他作为索引说明还有不足的地方。仔细看看可以发现平衡二叉树的每个节点只有两个孩子节点,如果一张表的数据量特别大,整棵树的高度也会随之上升。一个千万级别的表如果用平衡二叉树作为索引的话,树高将会达到二十多层。这也就意味着做一次查询需要二十多次磁盘io,这是一个不小的开销。

那么有没有能在大数据量的情况下,还能保持一个较小树高的树型结构呢?

B树和B+树

答案就是B树。上面我们说到了平衡二叉树的瓶颈在于一个节点只有两个孩子节点,而B树一个节点可以存放N个孩子节点,这就完美解决了树高的问题,我们可以把B树称为平衡多叉树,B树作为索引如下图所示:

但是以B树的结构作为索引仍有可以优化的地方,我们先看看最终的B+树,再仔细分析B+树在B树的基础上作了哪些改进,为什么B+树最终能够胜任索引的工作:

从图片中可以看到B+树同样是一棵多差平衡树,和B树一样很好地解决了树高的问题。

改进点一:

但仔细看可以发现,B树的节点中既存储索引,也存储表对应的数据;而B+树的非叶子节点是不存储数据的,只存储索引,数据全部存储在叶子节点上。

为什么要做这样的改进?我们做一次算术就知道了。

假设树高为2,主键ID为bigint类型,长度为8字节,节点指针为6字节,一行数据记录的大小为1k,一次io操作能获得一页16k的数据。

在索引为B+树的情况下,根节点能存储:16k / (6 + 8) = 1170 条索引指针;到了第一层,一共能指向 1170 * 1170 = 1368900 条索引指针;到了最底一层叶子节点,一个节点能存储16k / 1k = 16 条记录,一共能存储 1170 * 1170 * 16 = 21902400 条记录

在B树的情况下,由于非叶子节点使用了大量空间存储数据,存放的索引指针肯定就少,最终整棵树如果想要存储和B+树一样多的数据就必须要增加树高,这样一来就增加了磁盘io,所以说B+树作为索引的性能比B树高。

改进点二:

叶子节点之间使用指针连接,提高区间访问效率。如果我们要进行范围查询,可以轻松通过B+树叶子节点之间的指针进行遍历,减少了不必要的磁盘io。

总结

看到这里,相信大家对为什么Mysql的常用引擎都默认使用B+树作为索引已经有了初步的认知。我们只要牢记一点:索引是为了减少磁盘io提高查询性能而存在的。

最后回应一下为什么不常用哈希表和数组作为索引

哈希表虽然单一个值的查询效率很高,但是撑不住范围查询,哪个公司的业务还没个范围查询呢?

而数组虽然查询的效率高,但是增加和删除的效率低,由于记录在增加和删除的时候索引也得跟着维护,这会导致大数据量的情况下,增加或删除一条记录效率较低。

为什么Mysql的常用引擎都默认使用B+树作为索引?的更多相关文章

  1. MySQL 的常用引擎

    1. InnoDB InnoDB 的存储文件有两个,后缀名分别是 .frm 和 .idb,其中 .frm 是表的定义文件,而 idb 是数据文件. InnoDB 中存在表锁和行锁,不过行锁是在命中索引 ...

  2. mysql的常用引擎

    在MySQL数据库中,常用的引擎主要就是2个:Innodb和MyIASM. 首先: 1.简单介绍这两种引擎,以及该如何去选择.2.这两种引擎所使用的数据结构是什么. 1. a.Innodb引擎,Inn ...

  3. MySQL数据库常用引擎

    在MySQL数据库中,常用的引擎主要就是2个:Innodb和MyIASM. 首先: 1.简单介绍这两种引擎,以及该如何去选择.2.这两种引擎所使用的数据结构是什么. 1. a.Innodb引擎,Inn ...

  4. 为什么用B+树做索引&MySQL存储引擎简介

    索引的数据结构 为什么不是二叉树,红黑树什么的呢? 首先,一般来说,索引本身也很大,不可能全部存在内存中,因此索引往往以索引文件的方式存在磁盘上.然后一般一个结点一个磁盘块,也就是读一个结点要进行一次 ...

  5. 2020-05-18:MYSQL为什么用B+树做索引结构?平时过程中怎么加的索引?

    福哥答案2020-05-18:此答案来自群员:因为4.0成型那个年代,B树体系大量用于文件存储系统,甚至当年的Longhorn的winFS都是基于b树做索引,开源而且好用的也就这么个体系了.B+树的磁 ...

  6. Mysql 常用引擎的特点及选择使用策略

    Mysql 常用引擎的特点及选择使用策略 Mysql数据库常用存储引擎 Mysql数据库是一款开源的数据库,支持多种存储引擎的选择,比如目前最常用的存储引擎有:MyISAM,InnoDB,Memory ...

  7. mysql中有多种存储引擎,每种引擎都有自己的特色

    mysql中有多种存储引擎,每种引擎都有自己的特色. 用途: MyISAM:快读, Memory:内存数据, InnoDB:完整的事务支持 锁: MyISAM:全表锁定, Memory:全表锁定, I ...

  8. MySql的多存储引擎架构, 默认的引擎InnoDB与 MYISAM的区别(滴滴)

    1.存储引擎是什么? MySQL中的数据用各种不同的技术存储在文件(或者内存)中.这些技术中的每一种技术都使用不同的存储机制.索引技巧.锁定水平并且最终提供广泛的不同的功能和能力.通过选择不同的技术, ...

  9. 简单描述MySQL常用引擎的特点及MySQL的逻辑架构

    目录 表的分类数据库引擎? 首先得说说mysql的逻辑架构,它整体分为3层: 常用引擎: 补充知识点: 表的分类数据库引擎? 引擎是什么? 引擎就是一个系统最核心的部分,比如汽车的发动机,人的心脏 数 ...

随机推荐

  1. 组合数学--容斥原理&鸽巢原理

    一次会议由1990位数学家参加,每人至少有1327位合作者.证明可以找到4位数学家,他们当中每两个人都合作 优质解答 这题可以分两步来做.第一,先证明一定有三个人,他们相互合作过.可以先找两个相互合作 ...

  2. numpy的索引

    import numpy as np A =np.arange(3,15).reshape(3,4) print(A) #第一行 print(A[2]) #返回元素 print(A[1][2]) pr ...

  3. ConcurrentHashMap源码探究 (JDK 1.8)

    很早就知道在多线程环境中,HashMap不安全,应该使用ConcurrentHashMap等并发安全的容器代替,对于ConcurrentHashMap也有一定的了解,但是由于没有深入到源码层面,很多理 ...

  4. VirtualBox上使用kubeadm安装Kubernetes集群

    之前一直使用minikube练习,为了更贴近生产环境,使用VirtualBox搭建Kubernetes集群. 为了不是文章凌乱,把在搭建过程中遇到的问题及解决方法记在了另一篇文章:安装Kubernet ...

  5. plsql-工具安装部署及使用配置

    参考文档链接:https://blog.csdn.net/li66934791/article/details/83856225 简介: PL/SQL Developer是一个集成开发环境,专门开发面 ...

  6. ado.net DataSet

    一.概念 DataSet是ADO.NET的中心概念.可以把DataSet当成内存中的数据库,DataSet是不依赖于数据库的独立数据集合.所谓独立,就是说,即使断开数据链路,或者关闭数据库,DataS ...

  7. 54-with管理文件操作上下文

    目录 with管理文件操作上下文 with管理文件操作上下文 之前我们使用open()方法操作文件,但是open打开文件后我们还需要手动释放文件对操作系统的占用.其实我们可以更方便的打开文件,即Pyt ...

  8. 7-41 jmu-python-最佳身高 (10 分)

    最佳的情侣身高差遵循着一个公式:(女方的身高)×1.09 =(男方的身高).下面就请你写个程序,为任意一位用户计算他/她的情侣的最佳身高. 输入格式: 输入第一行给出正整数N(≤10),为前来查询的用 ...

  9. 2,Java中的数据结构

    1,字符串(String) ···String为特殊的引用类型,不可变. ···常用实例方法:     获取子串:substring(start, end);     获取索引:indexOf(cha ...

  10. 一篇文章彻底说清JS的深拷贝/浅拷贝

    一篇文章彻底说清JS的深拷贝and浅拷贝 这篇文章的受众 第一类,业务需要,急需知道如何深拷贝JS对象的开发者. 第二类,希望扎实JS基础,将来好去面试官前秀操作的好学者. 写给第一类读者 你只需要一 ...