妙啊!真实模拟面试 — 面试官究竟会怎么问 数据库索引呢?

什么是索引?

面试官:我看你项目中有作过 SQL 优化,那咱们今天就来聊聊索引吧。mysql

(索引能问些啥,无非是索引的概念、索引的使用规则、索引的分类、索引的原理。嘻嘻~我早有准备)web

:数据库中的索引,简单来讲呐,就比如一本书的目录,它能够帮咱们快速进行特定值的定位与查找,从而加快数据查询的效率。面试

若是咱们不使用索引,就必须从第 1 条记录开始依次日后查找,直到把全部的数据表都查找完,才能找到想要的数据。sql

记得点赞收藏加关注哦 ,须要下载PDF版本和更多知识点、面试题的朋友能够点一点下方连接免费领取数据库

连接:点这里!!! 799215493 暗号:CSDN服务器

在这里插入图片描述

面试官:那照你这么说,索引是否是越多越好?数据结构

索引是否是越多越好?

:固然索引也不是越多越好,索引也不是万能的,在有些状况下使用索引反而会让效率变低。jvm

索引的价值是帮咱们从海量数据中找到想要的数据,若是数据量少,那么是否使用索引对结果的影响并不大。svg

在数据表中的数据行数比较少的状况下,好比不到 1000 行,是不须要建立索引的。另外,当数据重复度大,好比高于 10% 的时候,也不须要对这个字段使用索引。微服务

好比,若是是性别这个字段,就不须要对它建立索引。这是为何呢?若是你想要在 100 万行数据中查找其中的 50 万行(好比性别为男的数据),一旦建立了索引,你须要先访问 50 万次索引,而后再访问 50 万次数据表,这样加起来的开销比不使用索引可能还要大。

索引的种类

面试官点点头,看起来对我以上的回答还算满意。接着又问:

面试官:那你说说索引有哪些种类?

按照功能逻辑分类

:从功能逻辑上说,索引主要有 4 种,分别是普通索引、惟一索引、主键索引和全文索引。

  • 普通索引是基础的索引,没有任何约束,主要用于提升查询效率。
  • 惟一索引就是在普通索引的基础上增长了数据惟一性的约束,在一张数据表里能够有多个惟一索引。
  • 主键索引在惟一索引的基础上增长了不为空的约束,也就是 NOT NULL+UNIQUE,一张表里最多只有一个主键索引。
  • 全文索引用的很少,MySQL 自带的全文索引只支持英文。咱们一般能够采用专门的全文搜索引擎,好比 ES(ElasticSearch) 和 Solr。

其实前三种索引(普通索引、惟一索引和主键索引)都是一类索引,只不过对数据的约束性逐渐提高。

在一张数据表中只能有一个主键索引,这是由主键索引的物理实现方式决定的,由于数据存储在文件中只能按照一种顺序进行存储。但能够有多个普通索引或者多个惟一索引。

按照物理实现方式分类

:按照物理实现方式,索引能够分为 2 种:汇集索引和非汇集索引。咱们也把非汇集索引称为二级索引或者辅助索引。

汇集索引能够按照主键来排序存储数据,这样在查找行的时候很是有效。

举个例子,若是是一本汉语字典,咱们想要查找“数”这个字,直接在书中找汉语拼音的位置便可,也就是拼音“shu”。这样找到了索引的位置,在它后面就是咱们想要找的数据行。

非汇集索引不会把索引指向的内容像汇集索引同样直接放到索引的后面,而是维护单独的索引表(只维护索引,不维护索引指向的数据),为数据检索提供方便。

咱们还以汉语字典为例,若是想要查找“数”字,那么按照部首查找的方式,先找到“数”字的偏旁部首,而后这个目录会告诉咱们“数”字存放到第多少页,咱们再去指定的页码找这个字。

也就是说系统会进行两次查找,第一次先找到索引,第二次找到索引对应的位置取出数据行。

汇集索引和非汇集索引两者的区别

其实回答到上面已经能够了,可是为了展现本身理解的透彻,我还作了如下阐述:

:汇集索引与非汇集索引的原理不一样,在使用上也有一些区别:

  1. 汇集索引的叶子节点存储的就是咱们的数据记录,非汇集索引的叶子节点存储的是数据位置。非汇集索引不会影响数据表的物理存储顺序。
  2. 一个表只能有一个汇集索引,由于只能有一种排序存储的方式,但能够有多个非汇集索引,也就是多个索引目录提供数据检索。
  3. 使用汇集索引的时候,数据的查询效率高,但若是对数据进行插入,删除,更新等操做,效率会比非汇集索引低。

索引的数据结构

面试官:你刚才从功能逻辑和物理实现的方式阐述了索引的分类,看来对索引的数据结构是有了解的,说一说你知道的索引数据结构就有哪些。

(这个简单啊,我脱口而出)

:Hash、B 树和 B+ 树均可以做为索引的数据结构,可是在 MySQL 中采用的是 B+ 树,B+ 树也是咱们经常使用的索引数据结构。

为何咱们经常使用 B+ 树做为索引的数据结构?

面试官:为何咱们经常使用 B+ 树做为索引的数据结构?其它树形结构不香吗?

:在回答这个问题以前我先说一下索引的存放位置,以及索引的数据结构设计好坏的评判标准。

索引的存放位置

:咱们知道,数据库服务器有两种存储介质,分别为硬盘和内存。内存属于临时存储,当发生意外时,好比说断电或者发生故障重启,会形成数据丢失;硬盘至关于永久存储介质,数据可持久化,这也是为何咱们须要把数据保存到硬盘上。

如何评价索引的数据结构设计好坏?

:虽然内存的读取速度很快,但咱们仍是须要将索引存放到硬盘上。所以,当咱们在硬盘上进行查询时,也就产生了硬盘的 I/O 操做。

咱们都知道,硬盘的 I/O 存取消耗的时间相比于内存的存取来讲,要高不少。咱们经过索引来查找某行数据的时候,须要计算产生的磁盘 I/O 次数,当磁盘 I/O 次数越多,所消耗的时间也就越大。

若是咱们能让索引的数据结构尽可能减小硬盘的 I/O 操做,所消耗的时间也就越小,那么这个索引的数据结构设计的也就越优。

二叉树

面试官点点头示意我继续说下去,为了对“为何咱们经常使用 B+ 树做为索引的数据结构”这个问题进行一个小白都能看懂的满意回答,我拿起了笔,图文并茂的从二叉树开始和面试官扯了起来。

:接下来讲说二叉树,咱们知道二分查找法是一种高效的数据检索方式,时间复杂度为 O(log2n),能够说检索速度是很快了。

以最基础的二叉搜索树(Binary Search Tree)为例,搜索某个节点和插入节点的规则同样,咱们假设搜索插入的数值为 key:

  1. 若是 key 大于根节点,则在右子树中进行查找;
  2. 若是 key 小于根节点,则在左子树中进行查找;
  3. 若是 key 等于根节点,也就是找到了这个节点,返回根节点便可。

举个例子,咱们对数列(25,18,36,9,20,32,41)创造出来的二分查找树以下图所示:

在这里插入图片描述
可是存在特殊的状况,二叉树的深度会很是大。好比咱们给出的数据顺序是 (9, 18, 20, 25, 32, 36, 41),创造出来的二分搜索树以下图所示:

在这里插入图片描述
如今这棵树也属于二分查找树,可是性能上已经退化成了一条链表,查找数据的时间复杂度变成了 O(n)。

咱们能够看出来第一个树的深度是 3,也就是说最多只需 3 次比较,就能够找到节点,而第二个树的深度是 7,最多须要 7 次比较才能找到节点。

平衡二叉搜索树

面试官:既然普通的二叉树不行,那平衡二叉搜索树怎么样?由于咱们知道它能够经过旋转的方式避免数据结构在特殊状况下退化成链表。

:我刚才提到过,数据查询的时间主要依赖于磁盘 I/O 的次数,即便是用了改进后的平衡二叉搜索树,树的深度也是 O(log2n),当 n 比较大时,深度也是比较高的,好比下图的状况:

在这里插入图片描述
每访问一次节点就须要进行一次磁盘 I/O 操做,对于上面的树来讲,咱们须要进行 5 次 I/O 操做。虽然平衡二叉树比较的效率高,可是树的深度也一样高,这就意味着磁盘 I/O 操做次数多,会影响总体数据查询的效率。

什么是 B 树?

:针对上面一样的数据,若是咱们把二叉树改为 M 叉树(M>2)的话,当 M=3 时,一样的 31 个节点能够由下面的三叉树来进行存储:
在这里插入图片描述
你能看到此时树的高度下降了,当数据量 N 大的时候,以及树的分叉数 M 大的时候,M 叉树的高度会远小于二叉树的高度。

若是用二叉树做为索引的实现结构,会让树变得很高,增长硬盘的 I/O 次数,影响数据查询的时间。所以一个节点就不能只有 2 个子节点,而应该容许有 M 个子节点 (M>2)。

而B 树的出现就是为了解决这个问题,B 树的英文是 Balance Tree,也就是平衡的多路搜索树,它的高度远小于平衡二叉树的高度。在文件系统和数据库系统中的索引结构常常采用 B 树来实现。

B 树的结构以下图所示:

在这里插入图片描述
B 树做为平衡的多路搜索树,它的每个节点最多能够包括 M 个子节点,M 称为 B 树的阶。同时你能看到,每一个磁盘块中包括了关键字和子节点的指针。若是一个磁盘块中包括了 x 个关键字,那么指针数就是 x+1。对于一个 100 阶的 B 树来讲,若是有 3 层的话最多能够存储约 100 万的索引数据。对于大量的索引数据来讲,采用 B 树的结构是很是适合的,由于树的高度要远小于二叉树的高度。

一个 M 阶的 B 树(M>2)有如下的特性:

  1. 根节点的儿子数的范围是 [2,M]。
  2. 每一个中间节点包含 k-1 个关键字和 k 个孩子,孩子的数量 = 关键字的数量 +1,k 的取值范围为 [ceil(M/2), M]。
  3. 叶子节点包括 k-1 个关键字(叶子节点没有孩子),k 的取值范围为 [ceil(M/2), M]。
  4. 假设中间节点节点的关键字为:Key[1], Key[2], …, Key[k-1],且关键字按照升序排序,即 Key[i]<Key[i+1]。此时 k-1 个关键字至关于划分了 k 个范围,也就是对应着 k 个指针,即为:P[1], P[2], …, P[k],其中 P[1] 指向关键字小于 Key[1] 的子树,P[i] 指向关键字属于 (Key[i-1], Key[i]) 的子树,P[k] 指向关键字大于 Key[k-1] 的子树。
  5. 全部叶子节点位于同一层。

上面那张图所表示的 B 树就是一棵 3 阶的 B 树。咱们能够看下磁盘块 2,里面的关键字为(8,12),它有 3 个孩子 (3,5),(9,10) 和 (13,15),你能看到 (3,5) 小于 8,(9,10) 在 8 和 12 之间,而 (13,15) 大于 12,恰好符合刚才咱们给出的特征。

而后咱们来看下如何用 B 树进行查找。假设咱们想要查找的关键字是 9,那么步骤能够分为如下几步:

  1. 咱们与根节点的关键字 (17,35)进行比较,9 小于 17 那么获得指针 P1;
  2. 按照指针 P1 找到磁盘块 2,关键字为(8,12),由于 9 在 8 和 12 之间,因此咱们获得指针 P2;
  3. 按照指针 P2 找到磁盘块 6,关键字为(9,10),而后咱们找到了关键字 9。

咱们能够看出来在 B 树的搜索过程当中,咱们比较的次数并很多,但若是把数据读取出来而后在内存中进行比较,这个时间就是能够忽略不计的。

而读取磁盘块自己须要进行 I/O 操做,消耗的时间比在内存中进行比较所须要的时间要多,是数据查找用时的重要因素,B 树相比于平衡二叉树来讲磁盘 I/O 操做要少,在数据查询中比平衡二叉树效率要高。

什么是 B+ 树?

:在最后说说 B+ 树,B+ 树是基于 B 树作出了改进,主流的 DBMS 都支持 B+ 树的索引方式,好比 MySQL。B+ 树和 B 树的差别在于如下几点:

  1. 有 k 个孩子的节点就有 k 个关键字。也就是孩子数量 = 关键字数,而 B 树中,孩子数量 = 关键字数 +1。
  2. 非叶子节点的关键字也会同时存在在子节点中,而且是在子节点中全部关键字的最大(或最小)。
  3. 非叶子节点仅用于索引,不保存数据记录,跟记录有关的信息都放在叶子节点中。而 B 树中,非叶子节点既保存索引,也保存数据记录。
  4. 全部关键字都在叶子节点出现,叶子节点构成一个有序链表,并且叶子节点自己按照关键字的大小从小到大顺序连接。

下图就是一棵 B+ 树,阶数为 3,根节点中的关键字 一、1八、35 分别是子节点(1,8,14),(18,24,31)和(35,41,53)中的最小值。每一层父节点的关键字都会出如今下一层的子节点的关键字中,所以在叶子节点中包括了全部的关键字信息,而且每个叶子节点都有一个指向下一个节点的指针,这样就造成了一个链表。

在这里插入图片描述
好比,咱们想要查找关键字 16,B+ 树会自顶向下逐层进行查找:

  • 与根节点的关键字 (1,18,35) 进行比较,16 在 1 和 18 之间,获得指针 P1(指向磁盘块 2)
  • 找到磁盘块 2,关键字为(1,8,14),由于 16 大于 14,因此获得指针 P3(指向磁盘块 7)
  • 找到磁盘块 7,关键字为(14,16,17),而后咱们找到了关键字 16,因此能够找到关键字 16 所对应的数据。

面试官:B+ 树整个过程一共进行了 3 次 I/O 操做,看起来 B+ 树和 B 树的查询过程差很少,那为何咱们使用 B+ 树更多呢?

:B+ 树和 B 树有个根本的差别在于,B+ 树的中间节点并不直接存储数据。这样的好处是:

  • 首先,B+ 树查询效率更稳定。由于 B+ 树每次只有访问到叶子节点才能找到对应的数据,而在 B树中,非叶子节点也会存储数据,这样就会形成查询效率不稳定的状况,有时候访问到了非叶子节点就能够找到关键字,而有时须要访问到叶子节点才能找到关键字。
  • 其次,B+ 树的查询效率更高,这是由于一般 B+ 树比 B 树更矮胖(阶数更大,深度更低),查询所须要的磁盘 I/O 也会更少。一样的磁盘页大小,B+ 树能够存储更多的节点关键字。

不只是对单个关键字的查询上,在查询范围上,B+ 树的效率也比 B 树高。这是由于全部关键字都出如今 B+ 树的叶子节点中,并经过有序链表进行了连接。而在 B 树中则须要经过中序遍历才能完成查询范围的查找,效率要低不少。

总的来讲,磁盘的 I/O 操做次数对索引的使用效率相当重要。虽然传统的二叉树数据结构查找数据的效率高,但很容易增长磁盘 I/O 操做的次数,影响索引使用的效率。所以在构造索引的时候,咱们更倾向于采用“矮胖”的数据结构。

B 树和 B+ 树均可以做为索引的数据结构,在 MySQL 中采用的是 B+ 树,B+ 树在查询性能上更稳定,在磁盘页大小相同的状况下,树的构造更加矮胖,所须要进行的磁盘 I/O 次数更少,更适合进行关键字的范围查询。

最后

在这里也为你们整理了各个知识点模块整理文档(微服务、数据库、mysql、jvm、Redis等都有)和更多大厂面试真题,有须要的朋友能够点一点下方连接免费领取

连接点这里!!! 799215493 暗号:CSDN

在这里插入图片描述
在这里插入图片描述