乐趣区

关于mysql:浅入浅出-MySQL-索引

索引是什么?为什么要有 mysql 索引,解决了什么问题,其底层的原理是什么?为什么应用 B + 树做为解决方案?用其余的像哈希索引或者 B 树不行吗?

简略理解索引

首先,索引(Index)是什么?如果我间接通知你索引是 数据库管理系统中的一个有序的数据结构,你可能会有点懵逼。

为了防止这种状况,我打算举几个例子来帮忙你更容易的意识 索引

咱们查问字典的时候能够依据字的部首、笔画来查找到对应的字,这样能够疾速的找到对应的字所在页,在字典结尾那玩意就叫 索引

还有一本书的目录,能够帮咱们疾速的跳到不同的章节,此时这里的目录也是 索引

甚至,景区的地图,会通知你你当初在哪里,其余景点在哪儿,这个地图从某些方面来说也是 索引

再联合开篇较业余的解释,你可能就可能了解索引是什么了。

为什么须要索引

理解了索引的概念,咱们就须要晓得为什么咱们须要索引?从刚刚的例子能够看进去,索引的存在的目标就是:

  • 字典中的索引帮忙咱们疾速的找到对应的字
  • 书的目录帮忙咱们疾速的跳到咱们须要看的章节
  • 景区的地图帮忙咱们疾速的找到想要去的景区的路

在数据库中,索引能够帮忙咱们疾速的查问到对应的数据行,从而顺利的取出所有列的数据。这个过程必须要 ,对于当初的 Web 利用来说,DB 如果响应慢,将会间接影响到整个申请的响应工夫,而这对用户体验来说是灾难性的。

对于点个按钮,等个好几秒才有返回,那么之后用户大概率是不会再应用你开发的利用了。

MySQL 中的索引

首先,MySQL 和索引其实没有间接的关系。索引其实是 MySQL 中应用的存储引擎 InnoDB 中的概念。在 InnoDB 中,索引分为:

  • 聚簇索引
  • 非聚簇索引

对于 聚簇索引 ,是 InnoDB 依据主键(Primary Key)构建的索引。你能够临时了解为 key 为主键,value 则是整行数据。并且一张表 只能有一个 聚簇索引。

当然,你能够不定义主键。然而 失常状况下 咱们都会创立一个枯燥递增的主键,或者是通过对立的 ID 生成算法生成。如果没有定义任何主键,InnoDB 会有本人的兜底策略。InnoDB 会抉择咱们定义的第一个 所有值的都不为空 惟一索引 作为 聚簇索引

不过理论的生产环境中,确实会有这样的 Corner Case。InnoDB 还有一个究极兜底,如果连仅剩的 惟一索引 也不符合要求,InnoDB 会本人创立一个暗藏的 6 个字节的主键 RowID,而后依据这个暗藏的主键来生成聚簇索引。

而对于 非聚簇索引 ,是依据指定的列创立的索引,也叫 二级索引(Secondary Index),一张表 最多能够创立 64 个二级索引 。key 为创立二级索引的列的值,value 为主键。换句话说,如果通过非聚簇索引查问,最终只能失去索引列自身的值 + 主键的值,如果想要获取到残缺的列数据,还须要依据失去的主键去聚簇索引中再查问一次,这个过程叫 回表

这里阐明一下,当初有很多的博客说,MySQL 应用 InnoDB 时,一张表最多只能创立 16 个索引,首先这是错的,显著是从其余的中央间接抄过来的,本人没有去做任何的验证。

在 MySQL 的官网文章中,明确的阐明了,一张表最多能够创立 64 个非聚簇索引,而且创立非聚簇索引时,列的数量不能超过 16 个。

留神,是创立非聚簇索引的列不能超过 16 个!

这也顺便提一下题外话,所谓的技术谨严,什么叫谨严?对你通过其余渠道获取到的常识,它最多叫 作者的观点 ,咱们持一种狐疑态度,并想方法本人去求证。求证后,它才会变成 事实

而不是对某些名词死记硬背,当初的新玩意层出不穷,但当你溯其本源,你会发现就那么回事。

索引底层原理

后面提到了 InnoDB 中索引的类型,简略的理解了其分类和区别,那 InnoDB 中的索引是如何做到减速查问的呢?其底层的原理是啥呢?InnoDB 中的索引的底层构造为 B+ 树,是 B 树的一个变种。

先给大家看看 B + 树到底长个什么鸟样,下图是一颗存储了数字「1-7」的 B + 树。

<img src=”https://tva1.sinaimg.cn/large/008i3skNgy1gqhyirkodxj30uh0akt9h.jpg” style=”zoom:67%;” />

能够看到,B+ 树中,每个节点能够有多个子节点,而像咱们平时相熟的二叉树中,每个节点最多只能有 2 个。并且,B+ 树中,节点的存储数据是有序的,而有序的数据结构就能够让咱们进行疾速的准确匹配和范畴查问。而且 B + 树中的叶子结点之间有指向下一个节点的指针,而 B 树中的叶子节点是没有的。

在 MySQL InnoDB 的理论实现中,页节点之间其实是个双链表,存储了别离指向上一个、下一个节点的指针

下图是蕴含了整数「1-7」的 B 树,这个图应该会帮忙你加深对两者区别的了解。

并且,在 B + 树中,除了叶子节点存储了实在的数据之外,其余的节点都只存储了指向下一节点的指针。换句话说,数据全副都在叶子节点上。而在 B 树中,所有的节点都能够存储数据,这是一个最次要的区别。

晓得了 B 树和 B + 树的根底构造长啥样之后,咱们须要再深刻理解 InnoDB 是如何利用 B + 树来存储数据的。首先,MySQL 并不会把数据存储在内存中,内存只是作为运行时的一种优化,对于 InnoDB 内存架构相干的货色,之前曾经写了一篇文章,感兴趣的能够先去看看。

InnoDB 会将数据存储在磁盘上,而当咱们查问数据的时候,OS 会将存储在磁盘上的数据一页一页的加载到内存里。这里的页是 OS 治理内存的一种形式,当其加载数据到内存时,会将某个磁盘块上的数据依照页的大小加载。在这里,你能够了解为 B 树中每个节点就是一个磁盘块。

那既然 B 树和 B + 树在查找的时候都须要进行 I/O 操作将须要的节点加载到内存,B+ 树绝对于 B 树的劣势到底在哪儿?

集体认为次要有三点。

一是 B + 树可能缩小 I/O 的次数。为啥呢?凭啥数据结构长的差不多,B+ 树就可能缩小 I/O 的次数?之前说到,单个节点就代表了一个磁盘块,而单个磁盘块的大小是固定的。B+ 树仅有叶子结点才存储值,绝对于所有节点都存残缺数据的 B 树而言,B+ 树中单个磁盘块可能包容更多的数据。

单个磁盘块,容量固定的前提下,存储的元素 大小越小 ,则可能存储的元素的 数量就会更多。换句话说,一次 I/O 可能把更多的数据加载进内存,而这些多加载的元素很可能是你会用到的,而这就肯定水平上能缩小 I/O 的次数。

除此之外,单个节点可能存储的元素增多了,还可能起到缩小树的高度的作用。

二是查问效率更加稳固。什么叫更稳固呢?那就在数据量雷同的状况下,不会因为你查问的数据 ID 不同而造成查问所消耗工夫天壤之别,换句话说,这次申请可能花了 10ms,下一次同样的申请啪的一下花了 20ms,这就让人很不能承受,合着接口的性能还要看你数据库的情绪?

那为什么说应用 B + 树就可能做到查问效率稳固呢?因为 B + 树非叶子结点不会存储数据,所以如果要获取到最终的数据,必然会查到叶子结点,换句话说,每次查问的 I/O 次数是雷同的。而 B 树因为所有节点均可存储数据,有的数据可能 1 次 I/O 就查问到了,而有的则须要查问到叶子结点才找到数据,而这就会带来查问效率的不稳固。

三是可能更好的反对范畴查问。那 B 树为啥就不能很好的反对呢?让咱们回到 B 树这张图。

假如咱们须要查问 [3, 5] 这个区间内的数据,会经验什么呢?不废话,间接把图给进去。

能够看到,如果到叶子结点依然没有查问到残缺的数据,会从新返回到根结点再次进行遍历。而反观 B+ 树,当找到了叶子结点之后就能够通过叶子结点之间的指针间接进行链表遍历,能够大大的晋升范畴查问的效率。

晓得了这点之后,触类旁通就可能晓得,为什么 InnoDB 不应用 Hash 在做底层的数据结构了。即便查问时 Hash 的工夫复杂度甚至能做到 O(1)

最初聊聊 I/O

全篇提到了很屡次 I/O,以及在 MySQL 的索引设计中,须要尽量的缩小 I/O 次数,为啥呢?是因为 I/O 很低廉。当咱们执行一次 I/O,到底产生了什么?

原本像具体讲讲磁盘构造的,然而看了一眼篇幅,曾经快超了,所以这里就简略的聊聊就好

机械硬盘中,一次 I/O 操作,由三个步骤组成:

首先须要 寻道,寻道是指磁盘的磁头挪动道磁盘上的磁道下面,这个工夫个别在 3 -15ms 内。

而后是 旋转,磁盘会将存储对应数据的盘片旋转至磁头下方,这又花掉 2ms 左右,具体的时延与磁盘的转速无关。

最初是 数据传输

一波操作下来,破费就在 10ms 左右。不要认为 10ms 还好 … 比照于 SSD(固态硬盘)和内存的微秒、纳秒来说,几乎有着天壤之别。

这也是为啥在 MySQL 中,随机 I/O 对其查问的性能影响很大的起因。

好了以上就是本篇博客的全部内容了,欢送微信搜寻关注【SH 的全栈笔记 】,回复【 队列】获取 MQ 学习材料,蕴含根底概念解析和 RocketMQ 具体的源码解析,继续更新中。

如果你感觉这篇文章对你有帮忙,还麻烦 点个赞 关个注 分个享 留个言

退出移动版