MySQL索引面试题有哪些

技术MySQL索引面试题有哪些这篇文章主要介绍“MySQL索引面试题有哪些”,在日常操作中,相信很多人在MySQL索引面试题有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”MySQL索

本文主要介绍“MySQL索引面试题有哪些”。在日常操作中,相信很多人对MySQL索引面试题中的问题都有疑问。边肖查阅了各种资料,整理出简单易用的操作方法,希望能帮你解答“MySQL索引面试题有哪些”的疑惑!接下来,请和边肖一起学习!

1、面试真题

能介绍一下MySQ索引的原理和数据结构吗?

B树和B树有什么区别?

MySQL聚集索引和非聚集索引有什么区别?

它们是如何分开存放的?

使用MySQL索引的原则是什么?

如何使用MySQL复合索引?

2、面试官心理分析

对于离数据库30k以内的工程师来说,这是一个必须问的问题,如果你问数据库的问题,你必须问mysql。n年前,java工程师可能会出去面试。神谕的技能是杀手。现在没人说了解甲骨文是一件好事。现在,熟悉大数据hadoop、hbase等技术是加分项。

3、面试题剖析

3.1 索引的数据结构是什么

其实就是让你说说mysql的索引底层的数据结构。如果不好,会要求你在现场画出索引的数据结构,然后再询问mysql索引的常用使用原则。如果不好,会用一个SQL问你,如何基于这个SQL建立索引?

指数是多少?这个问题太基础了。众所周知,mysql index简单来说就是用一个数据结构来组织某一列的数据,然后如果要根据那一列的数据进行查询,不需要扫描整个表,只需要根据那个特定的数据结构找到那一列的值,然后找到对应行的物理地址就可以了。

然后,回答一个面试官的问题,mysql索引是如何实现的?

答案是,它不是二叉树,也不是乱树,而是B树。很多人会这样回答,然后面试官肯定会问问题,那你能说说B树吗?

但是在讨论b树之前,我们先来讨论一下b树是什么。从数据结构来看,B-树应满足以下条件:

(1)d是大于1的正整数,称为B-Tree的度。

(2)h为正整数,称为B-Tree的高度。

(3)每个非叶节点由n-1个键和n个指针组成,其中d=n=2d。

(4)每个叶节点至少包含一个键和两个指针,最多包含2d-1键和2d指针,全部为空。

(5)所有叶节点深度相同,等于树的高度h。

(6)键和指针相互间隔,节点的两端都是指针。

(7)节点中的键从左到右按非递减顺序排列。

(8)所有节点形成树形结构。

(9)每个指针要么为空,要么指向另一个节点。

(10)如果指针位于节点的最左侧且不为空,则它指向该节点的所有键都小于v(key1),其中v(key1)是该节点第一个键的值。

(11)如果一个指针位于节点的最右侧,并且不为空,则它指向该节点的所有键都大于v(keym),其中v(keym)是该节点最后一个键的值。

(12)如果节点节点中指针的左右相邻键分别为V(易科和易科1),且不为空,则它指向该节点的所有键都小于V(易科1)且大于v(keyi 1)。

我也是从网上找到了上面的规律。老实说,很少有java程序员能耐心地阅读或记忆它。知道它是一棵树就好了。让我们给你看一张在线地图:

例如,我们现在有一个表:

我们现在为id: 15,56,77,20,49选择*从表中选择=49选择*从表中选择=15MySQL索引面试题有哪些

反正大概就是上面那个样子。搜索时,是从根节点开始的二进制搜索。很高兴知道这是件大事。我没有足够的时间深入讲里面的数学和算法问题,面试官也没想到你会讲里面的数学和算法问题,因为我觉得他自己都记不住。

好了,b树到此为止。让我们看看下一个,B树。b树是b树的变种。什么是变体?也就是说,有些事情在原则上是不一样的,有点

有点变化,同样的一套数据,放b-树和b+树看着排列不太一样的。而mysql里面一般就是b+树来实现索引,所以b+树很重要。

b+树跟b-树不太一样的地方在于:

  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区

  2.  每个节点的指针上限为2d而不是2d+1。

  3.  内节点不存储data,只存储key;

叶子节点不存储指针。

这图我就不自己画了,网上弄个图给大家瞅一眼:

MySQL索引面试题有哪些

select * from table where id = 15  select * from table where id>=18 and id<=49

但是一般数据库的索引都对b+树进行了优化,加了顺序访问的指针,如网上弄的一个图,这样在查找范围的时候,就很方便,比如查找18~49之间的数据:

MySQL索引面试题有哪些

其实到这里,你就差不多了,你自己仔细看看上面两个图,b-树和b+树都现场画一下,然后给说说区别,和通过b+树查找的原理即可。

接着来聊点稍微高级点的,因为上面说的只不过都是最基础和通用的b-树和b+树罢了,但是mysql里不同的存储引擎对索引的实现是不同的。

3.2 myism存储引擎的索引实现

先来看看myisam存储引擎的索引实现。就拿上面那个图,咱们来现场手画一下这个myisam存储的索引实现,在myisam存储引擎的索引中,每个叶子节点的data存放的是数据行的物理地址,比如0x07之类的东西,然后我们可以画一个数据表出来,一行一行的,每行对应一个物理地址。

索引文件

MySQL索引面试题有哪些

id=15,data:0x07,0a89,数据行的物理地址

数据文件单独放一个文件

MySQL索引面试题有哪些

select * from table where id = 15 -> 0x07物理地址 -> 15,张三,22

myisam最大的特点是数据文件和索引文件是分开的,大家看到了么,先是索引文件里搜索,然后到数据文件里定位一个行的。

3.3 innodb存储引擎的索引

好了,再来看看innodb存储引擎的索引实现,跟myisam最大的区别在于说,innodb的数据文件本身就是个索引文件,就是主键key,然后叶子节点的data就是那个数据的所在行。我们还是用上面那个索引起来现场手画一下这个索引好了,给大家来感受一下。

MySQL索引面试题有哪些

innodb存储引擎,要求必须有主键,会根据主键建立一个默认索引,叫做聚簇索引,innodb的数据文件本身同时也是个索引文件,索引存储结构大致如下:

15,data:0x07,完整的一行数据,(15,张三,22)  22,data:完整的一行数据,(22,李四,30)

就是因为这个原因,innodb表是要求必须有主键的,但是myisam表不要求必须有主键。另外一个是,innodb存储引擎下,如果对某个非主键的字段创建个索引,那么最后那个叶子节点的值就是主键的值,因为可以用主键的值到聚簇索引里根据主键值再次查找到数据,即所谓的回表,例如:

select * from table where name = &lsquo;张三&rsquo;

先到name的索引里去找,找到张三对应的叶子节点,叶子节点的data就是那一行的主键,id=15,然后再根据id=15,到数据文件里面的聚簇索引(根据主键组织的索引)根据id=15去定位出来id=15这一行的完整的数据

所以这里就明白了一个道理,为啥innodb下不要用UUID生成的超长字符串作为主键?因为这么玩儿会导致所有的索引的data都是那个主键值,最终导致索引会变得过大,浪费很多磁盘空间。

还有一个道理,一般innodb表里,建议统一用auto_increment自增值作为主键值,因为这样可以保持聚簇索引直接加记录就可以,如果用那种不是单调递增的主键值,可能会导致b+树分裂后重新组织,会浪费时间。

3.4 索引的使用规则

一般来说跳槽时候,索引这块必问,b+树索引的结构,一般是怎么存放的,出个题,针对这个SQL,索引应该怎么来建立

select * from table where a=1 and b=2 and c=3,你知道不知道,你要怎么建立索引,才可以确保这个SQL使用索引来查询

好了,各位同学,聊到这里,你应该知道具体的myisam和innodb索引的区别了,同时也知道什么是聚簇索引了,现场手画画,应该都ok了。然后我们再来说几个最最基本的使用索引的基本规则。

其实最基本的,作为一个java码农,你得知道最左前缀匹配原则,这个东西是跟联合索引(复合索引)相关联的,就是说,你很多时候不是对一个一个的字段分别搞一个一个的索引,而是针对几个索引建立一个联合索引的。

给大家举个例子,你如果要对一个商品表按照店铺、商品、创建时间三个维度来查询,那么就可以创建一个联合索引:shop_id、product_id、gmt_create

一般来说,你有一个表(product):shop_id、product_id、gmt_create,你的SQL语句要根据这3个字段来查询,所以你一般来说不是就建立3个索引,一般来说会针对平时要查询的几个字段,建立一个联合索引

后面在java系统里写的SQL,都必须符合最左前缀匹配原则,确保你所有的sql都可以使用上这个联合索引,通过索引来查询

create index (shop_id,product_id,gmt_create)

(1)全列匹配

这个就是说,你的一个sql里,正好where条件里就用了这3个字段,那么就一定可以用到这个联合索引的:

select * from product where shop_id=1 and product_id=1 and gmt_create=&rsquo;2018-01-01 10:00:00&rsquo;

(2)最左前缀匹配

这个就是说,如果你的sql里,正好就用到了联合索引最左边的一个或者几个列表,那么也可以用上这个索引,在索引里查找的时候就用最左边的几个列就行了:

select * from product where shop_id=1 and product_id=1,这个是没问题的,可以用上这个索引的

(3)最左前缀匹配了,但是中间某个值没匹配

这个是说,如果你的sql里,就用了联合索引的第一个列和第三个列,那么会按照第一个列值在索引里找,找完以后对结果集扫描一遍根据第三个列来过滤,第三个列是不走索引去搜索的,就是有一个额外的过滤的工作,但是还能用到索引,所以也还好,例如:

select * from product where shop_id=1 and gmt_create=&rsquo;2018-01-01 10:00:00&rsquo;

就是先根据shop_id=1在索引里找,找到比如100行记录,然后对这100行记录再次扫描一遍,过滤出来gmt_create=&rsquo;2018-01-01 10:00:00&rsquo;的行

这个我们在线上系统经常遇到这种情况,就是根据联合索引的前一两个列按索引查,然后后面跟一堆复杂的条件,还有函数啥的,但是只要对索引查找结果过滤就好了,根据线上实践,单表几百万数据量的时候,性能也还不错的,简单SQL也就几ms,复杂SQL也就几百ms。可以接受的。

(4)没有最左前缀匹配

那就不行了,那就在搞笑了,一定不会用索引,所以这个错误千万别犯

select * from product where product_id=1,这个肯定不行

(5)前缀匹配

这个就是说,如果你不是等值的,比如=,>=,<=的操作,而是like操作,那么必须要是like &lsquo;XX%&rsquo;这种才可以用上索引,比如说

select * from product where shop_id=1 and product_id=1 and gmt_create like &lsquo;2018%&rsquo;

6)范围列匹配

如果你是范围查询,比如>=,<=,between操作,你只能是符合最左前缀的规则才可以范围,范围之后的列就不用索引了

select * from product where shop_id>=1 and product_id=1

这里就在联合索引中根据shop_id来查询了

(7)包含函数

如果你对某个列用了函数,比如substring之类的东西,那么那一列不用索引

select * from product where shop_id=1 and 函数(product_id) = 2

上面就根据shop_id在联合索引中查询

3.5 索引的缺点以及使用注意

索引是有缺点的,比如常见的就是会增加磁盘消耗,因为要占用磁盘文件,同时高并发的时候频繁插入和修改索引,会导致性能损耗的。

我们给的建议,尽量创建少的索引,比如说一个表一两个索引,两三个索引,十来个,20个索引,高并发场景下还可以。

字段,status,100行,status就2个值,0和1

你觉得你建立索引还有意义吗?几乎跟全表扫描都差不多了

select * from table where status=1,相当于是把100行里的50行都扫一遍

你有个id字段,每个id都不太一样,建立个索引,这个时候其实用索引效果就很好,你比如为了定位到某个id的行,其实通过索引二分查找,可以大大减少要扫描的数据量,性能是非常好的

在创建索引的时候,要注意一个选择性的问题,select count(discount(col)) / count(*),就可以看看选择性,就是这个列的唯一值在总行数的占比,如果过低,就代表这个字段的值其实都差不多,或者很多行的这个值都类似的,那创建索引几乎没什么意义,你搜一个值定位到一大坨行,还得重新扫描。

就是要一个字段的值几乎都不太一样,此时用索引的效果才是最好的

还有一种特殊的索引叫做前缀索引,就是说,某个字段是字符串,很长,如果你要建立索引,最好就对这个字符串的前缀来创建,比如前10个字符这样子,要用前多少位的字符串创建前缀索引,就对不同长度的前缀看看选择性就好了,一般前缀长度越长选择性的值越高。

好了,各位同学,索引这块能聊到这个程度,或者掌握到这个程度,其实普通的互联网系统中,80%的活儿都可以干了,因为在互联网系统中,一般就是尽量降低SQL的复杂度,让SQL非常简单就可以了,然后搭配上非常简单的一个主键索引(聚簇索引)+ 少数几个联合索引,就可以覆盖一个表的所有SQL查询需求了。更加复杂的业务逻辑,让java代码里来实现就ok了。

大家要明白,SQL达到95%都是单表增删改查,如果你有一些join等逻辑,就放在java代码里来做。SQL越简单,后续迁移分库分表、读写分离的时候,成本越低,几乎都不用怎么改造SQL。

我这里给大家说下,互联网公司而言,用MySQL当最牛的在线即时的存储,存数据,简单的取出来;不要用MySQL来计算,不要写join、子查询、函数放MySQL里来计算,高并发场景下;计算放java内存里,通过写java代码来做;可以合理利用mysql的事务支持

到此,关于“MySQL索引面试题有哪些”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/133173.html

(0)

相关推荐

  • 如何使用SPNEGO配置身份验证

    技术如何使用SPNEGO配置身份验证这篇文章给大家介绍如何使用SPNEGO配置身份验证,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Cloudera Manager 6.3和更高版本支持使用SPNE

    攻略 2021年11月10日
  • MySQL常用分库分表方案有哪些

    技术MySQL常用分库分表方案有哪些这篇文章主要为大家展示了“MySQL常用分库分表方案有哪些”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“MySQL常用分库分表方案有哪些”

    攻略 2021年11月14日
  • python发qq消息轰炸虐狗好友思路分析

    技术python发qq消息轰炸虐狗好友思路分析本篇内容介绍了“python发qq消息轰炸虐狗好友思路分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希

    攻略 2021年11月4日
  • 条条大路通罗马下一句,条条大路通罗马出自谁的什么文章

    技术条条大路通罗马下一句,条条大路通罗马出自谁的什么文章“条条大路通罗马”原话是“All Roads Lead to Rome”条条大路通罗马下一句,这是一句谚语,出自《罗马典故》,是指做成一件事的方法不只一种,人生的路

    生活 2021年10月22日
  • 如何理解LayaAir中的EventDispatcher类

    技术如何理解LayaAir中的EventDispatcher类这篇文章将为大家详细讲解有关如何理解LayaAir中的EventDispatcher类,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后

    攻略 2021年11月11日
  • MongoDB可视化工具的使用方法

    技术MongoDB可视化工具的使用方法今天就跟大家聊聊有关MongoDB可视化工具的使用方法,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。 MongoDB 是一种

    攻略 2021年11月3日