一、前言

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

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

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

二、索引的本质

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

如果把查询一条数据分为到磁盘中查询和比对查询条件两步的话,到磁盘中查询的时间会远远大于比对查询条件的时间,这意味着在一次查询中,磁盘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. 腾讯入股Snap,能救“阅后即焚”的命吗?

    ​ ​   互联网社交的强大包容性,让各种社交形式都能有着较多的受众群体.普适性极广的QQ.微信."脸谱":专攻陌生人社交的陌陌:让人们发布意见的微博--当然也少不了"阅 ...

  2. c#或者C#.net中的“ToolTip”是“System.Windows.Forms.ToolTip”和“DevComponents.DotNetBar.ToolTip”之间的不明确的引用

    “ToolTip”是“System.Windows.Forms.ToolTip”和“DevComponents.DotNetBar.ToolTip”之间的不明确的引用 ,在编程时,有时候会编译出现不明 ...

  3. C++走向远洋——60(十四周阅读程序、STL中的简单容器和迭代器)

    */ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:text.cpp * 作者:常轩 * 微信公众号:Worldhe ...

  4. 基于python openOPC的监控页面一

    笔者涉猎的工业领域项目遇到一个需求,需要把底层设备(表记)的状态和运行数据集中放到一个监控画面进行展示,数据需要在界面端实时进行刷新,类似网友的例子,如下图(侵删) 数据需要实时主动刷新,笔者基于多年 ...

  5. 二叉堆的BuildHeap操作

    优先队列(二叉堆)BuildHeap操作 \(BuildHeap(H)\)操作把\(N\)个关键字作为输入并把它们放入空堆中.显然,这可以使用\(N\)个相继的\(Insert\)操作来完成.由于每个 ...

  6. Markdown 语法简要规则

    Markdown简介 Markdown 是一种轻量级的「标记语言」,它的优点很多,目前也被越来越多的写作爱好者,撰稿者广泛使用.看到这里请不要被「标记」.「语言」所迷惑,Markdown 的语法十分简 ...

  7. 【Amaple教程】5. 插件

    Amaple 拥有非常强大插件功能,这也是它的突出功能之一,Amaple插件一般表现为功能块(函数)或功能块(包含一系列函数和属性的Object对象),它除了支持Amaple规范定义的插件外,还支持所 ...

  8. 伪元素 before 和 after 初探

    伪元素 before 和 after 初探 使用了 CodePen 做演示,欢迎点击预览 定义 首先来看 MDN 的定义: ::before 创建一个伪元素,作为已选中元素的第一个子元素,常通过 co ...

  9. Python-PhantomJS的安装和使用

    PhantomJS无需浏览器的Web测试: PhantomJS官网下载地址:https://phantomjs.org/download.html 下载PhantomJS zip文件,解压放置在D:\ ...

  10. 学以致用:手把手教你撸一个工具库并打包发布,顺便解决JS浮点数计算精度问题

    本文讲解的是怎么实现一个工具库并打包发布到npm给大家使用.本文实现的工具是一个分数计算器,大家考虑如下情况: \[ \sqrt{(((\frac{1}{3}+3.5)*\frac{2}{9}-\fr ...