草庐IT

来自面试官二面MySQL索引的连续灵魂拷问

囧么肥事 2023-03-28 原文

【来自面试官二面MySQL索引的连续灵魂拷问】

本期主要面试考点

面试官考点之谈谈索引维护过程?页分裂?页合并? 面试官考点之简述一下查询时B+树索引搜索过程? 面试官考点之什么是回表? 面试官考点之什么是索引覆盖?使用场景? 面试官考点之什么情况下会索引失效? 面试官考点之哪些情况下,可能会面临索引失效的问题? 面试官考点之or走索引和索引失效分别是什么场景? 面试官考点之哪些情况下需要创建索引? 面试官考点之联合索引之最左前缀原则? 面试官考点之索引下推场景? 我是肥哥,一名不专业的面试官!

我是囧囧,一名积极找工作的小菜鸟!

囧囧表示:小白面试最怕的就是面试官问的知识点太笼统,自己无法快速定位到关键问题点!!!



面试官考点之谈谈索引维护过程?页分裂?页合并?

B+树为了维护索引有序性,在插入删除的时候需要做必要的维护,必要时候可能涉及到页分裂,页合并过程!

首先假设每个叶子节点(数据页或磁盘块)只能存储3条索引和数据记录,如图

情况1、新增行记录,ID=3,此时【数据页1】未满,只需要在data2后新增ID=3的行记录,B+树整体结构不需要进行调整

情况2、新增行记录,ID=8,此时【数据页2】已满,这时候需要申请一个新的数据页,然后挪动部分数据过去。这个过程称为页分裂

页分裂过程消耗性能,同时空间利用率也降低了

有分裂就有合并,当相邻两个页由于删除了数据,利用率很低之后,会将数据页做合并。合并的过程,可以认为是分裂过程的逆过程

当相邻两个页由于删除了数据,利用率很低之后,会将数据页做合并。合并的过程,可以认为是分裂过程的逆过程。

【数据页2】删除了ID=7,ID=8的行记录,此时【数据页2】【数据页3】利用率很低,将进行页合并。

面试官考点之简述一下查询时B+树索引搜索过程?

准备一张用户表,其中id为主键,age为普通索引

CREATE TABLE `user` ( `id` int(11) PRIMARY KEY, `name` varchar(255) DEFAULT NULL, `age` int(11) DEFAULT NULL KEY `idx_age` (`age`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; select * from user where age=22 简述一下B+树索引搜索过程?

假设要查询的记录

id=5,name="张三",age=22 MySQL为每个索引分别维护了一棵B+Tree索引树,

主键索引非叶子节点维护了索引键,叶子节点存储行数据;

非主键索引也称为二级索引,非叶子节点存储主键;

B+树索引搜索过程

搜索条件 age=22,可走idx_age索引,首先加载idx_age索引树,找到age=22的记录,取得id=5

回表搜索,加载主键索引树,找到id=22的记录,取得整行数据

面试官考点之什么是回表?

idx_age二级索引树找到主键id后,回到id主键索引搜索的过程,就称为回表。

并非所有非主键索引搜索,都需要进行回表搜索,也就是下面要说的索引覆盖。

面试官考点之什么是索引覆盖?使用场景?

在上面提到的例子中,由于查询结果所需要的数据只在主键索引上有,所以不得不回表。

如果在查询的数据列里面,直接从索引列就能取到想要的结果,就不需要再回表去查,也称之为索引覆盖!

索引覆盖的优点

  1. 可以避免对Innodb主键索引的二次查询
  2. 可以避免MyISAM表进行系统调用
  3. 可以优化缓存,减少磁盘IO操作
修改一下上述栗子,满足索引覆盖条件?

select id, age from user where age=22 查询的信息,id,age都可以直接在idx_age 索引树中获取,不需要回表搜索。

由于覆盖索引可以减少树的搜索次数,显著提升查询性能,所以使用覆盖索引是一个常用 的性能优化手段。

索引是一把双刃剑,提供快速排序搜索的同时,索引字段的维护也是要付出相应的代价的。

因此,在建立冗余索引来支持覆盖索引时就需要权衡考虑了

面试官考点之索引失效?

创建的索引,到底有没有生效,或者说SQL语句有没有使用索引查询?

一个最常见的查询场景,建立idx_name索引

select * from t_user where user_name like '%mayun100%';
这条查询是否走索引?

select * from t_user where user_name like 'mayun100%';
这条查询是否走索引?

面试官考点之有哪些情况下,可能会面临索引失效的问题?

  1. like通配符,左侧开放情况下,全表扫描
  2. or条件筛选,可能会导致索引失效
  3. where中对索引列使用mysql的内置函数,一定失效
  4. where中对索引列进行运算(如,+、-、*、/),一定失效
  5. 类型不一致,隐式的类型转换,导致的索引失效
  6. where语句中索引列使用了负向查询,可能会导致索引失效 负向查询包括:NOT、!=、<>、!<、!>、NOT IN、NOT LIKE等。其中!< !> 为SQLServer语法。
  7. 索引字段可以为null,使用is null或is not null时,可能会导致索引失效
  8. 隐式字符编码转换导致的索引失效
  9. 联合索引中,where中索引列违背最左匹配原则,一定会导致索引失效
  10. MySQL优化器的最终选择,不走索引

面试官考点之or走索引和索引失效分别是什么场景?

or走索引和索引失效分别是什么场景?

OR 连接的是同一个字段,相同走索引

explain select * from t_user where user_name = 'mayun10' or user_name = 'mayun1000'

OR 连接的是两个不同的字段,不走索引

给address列增加索引

alter table t_user add index idx_address(address); explain select * from t_user where user_name = 'mayun10' or address = '浙江杭州12';
OR 连接的是两个不同字段,如果两个字段皆有索引,走索引

(插播,下一期:《MySQL面试小抄》几种索引失效场景验证)

尽请关注:囧么肥事

面试小抄系列。

面试官考点之哪些情况下需要创建索引?

1.主键自动建立唯一索引

2.频繁查询的字段

3.JOIN 关联查询,作为外键关系的列建立索引

4.单键/组合索引的选择问题,高并发下倾向创建组合索引,创建时遵循最左前缀匹配原则

5.ORDER BY 查询中排序的字段,排序字段通过索引访问大幅提高排序速度

6.GROUP BY 需要分组字段或查询中统计字段

面试官考点之联合索引之最左前缀原则

MySQL建立多列索引(联合索引)有最左前缀的原则,即最左优先

当MySQL建立的是联合索引,假设以(a,b,c) 列作为联合索引,那么MySQL建树规则是什么?

我们知道MySQL会为每一个索引维护一颗B+Tree,非叶子节点存储索引key,叶子节点存储行数据data。

联合索引(a,b,c) 相当于建立了 (a), (a,b), (a,b,c) 三个索引,MySQL组装索引树时,是按照从左到右的顺序来建立B+Tree的联合索引树的。

匹配索引情况一

**假设(a,b,c)**索引要搜索的值为('张三', 21, 100) ,检索数据时,匹配的顺序就是a,b,c。

B+Tree会优先比较a来确定下一步的所搜方向,如果a相同再依次比较b和c,最后得到检索的数据;

匹配索引情况二

**假设(a,c)**索引要搜索的值为('张三', 100) ,检索数据时,匹配的顺序就是a,b,c。

B+Tree使用a来指定搜索方向,但下一个字段b缺失,所以只能把a等于张三的数据都找到,然后再匹配c是100的数据。

匹配索引情况三

**假设(b,c)**索引要搜索的值为('张三', 21) ,检索数据时,无匹配顺序

B+Tree不知道下一步该查哪个节点,因为建立搜索树的时候a是第一个比较因子,必须要先根据a来搜索才能知道下一步去哪里查询。此时索引失效!

索引项是按照索引定义里面出现的字段顺序排序的,最左前缀可以是联合索引的最左N个字段,也可以是字符串索引的最左M个字符。

面试官考点之索引下推场景?

索引下推,即减少二级索引回表搜索次数!!!

通俗说,减少查询主键索引树次数,减少磁盘IO

建立联合索引 idx_age_weight

select * from user where age = 11 and weight = 98 5.6之前搜索过程是

在idx_age_weight 索引树中匹配出所有的 age = 11 索引,拿到主键id,回表去一条条再比对weight字段

如下图,需要进行3次回表搜索操作

5.6后的搜索过程是 在idx_age_weight 索引树中匹配出所有的 age = 11 索引,顺便对weight字段进行判断,过滤掉weight = 100的记录,然后再进行回表搜索。

如下图,只需要进行2次回表搜索操作`


推荐MySQL相关休闲阅读

第一段,索引面试题推荐阅读一:【来自面试官一面MySQL索引的连续灵魂拷问】

第二段,索引面试题推荐阅读二:【来自面试官二面MySQL索引的连续灵魂拷问】

第三段,索引失效场景面试题推荐阅读:【面试官:说说你遇到的MySQL索引失效场景吧,你是如何解决的?】

第四段,查询缓存面试题推荐阅读:【面试官:什么场景下会导致MySQL缓存失效?生产环境到底要不要开启MySQL缓存?】

第五段,待更新?推荐休闲阅读:【囧么肥事】

更多精彩内容,欢迎关注微信公众号:囧么肥事 (或搜索:jiongmefeishi)

有关来自面试官二面MySQL索引的连续灵魂拷问的更多相关文章

  1. ruby - 如何以所有可能的方式将字符串拆分为长度最多为 3 的连续子字符串? - 2

    我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123

  2. 使用canal同步MySQL数据到ES - 2

    文章目录一、概述简介原理模块二、配置Mysql使用版本环境要求1.操作系统2.mysql要求三、配置canal-server离线下载在线下载上传解压修改配置单机配置集群配置分库分表配置1.修改全局配置2.实例配置垂直分库水平分库3.修改group-instance.xml4.启动监听四、配置canal-adapter1修改启动配置2配置映射文件3启动ES数据同步查询所有订阅同步数据同步开关启动4.验证五、配置canal-admin一、概述简介canal是Alibaba旗下的一款开源项目,Java开发。基于数据库增量日志解析,提供增量数据订阅&消费。Git地址:https://github.co

  3. 【Java 面试合集】HashMap中为什么引入红黑树,而不是AVL树呢 - 2

    HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候

  4. ruby-on-rails - 协会的 Rails 索引 - 2

    我发现自己需要这个。假设cart是一个包含用户列表的模型。defindex_of_itemcart.users.each_with_indexdo|u,i|ifu==current_userreturniendend获取此类关联索引的更简单方法是什么? 最佳答案 indexArray上的方法与您的index_of_item方法相同,例如cart.users.index(current_user)返回数组中第一个对象的索引==给obj。如果未找到匹配项,则返回nil。 关于ruby-on-

  5. ruby - Rails -- :id attribute? 所需的数据库索引 - 2

    因此,当我遵循MichaelHartl的RubyonRails教程时,我注意到在用户表中,我们为:email属性添加了一个唯一索引,以提高find的效率方法,因此它不会逐行搜索。到目前为止,我们一直在根据情况使用find_by_email和find_by_id进行搜索。然而,我们从未为:id属性设置索引。:id是否自动索引,因为它在默认情况下是唯一的并且本质上是顺序的?或者情况并非如此,我应该为:id搜索添加索引吗? 最佳答案 大多数数据库(包括sqlite,这是RoR中的默认数据库)会自动索引主键,对于RailsMigration

  6. ruby-on-rails - 无法安装 mysql2 0.3.14 gem - 2

    我看到其他人也遇到过类似的问题,但没有一个解决方案对我有用。0.3.14gem与其他gem文件一起存在。我已经完全按照此处指示完成了所有操作:https://github.com/brianmario/mysql2.我仍然得到以下信息。我不知道为什么安装程序指示它找不到include目录,因为我已经检查过它存在。thread.h文件存在,但不在ruby​​目录中。相反,它在这里:C:\RailsInstaller\DevKit\lib\perl5\5.8\msys\CORE\我正在运行Windows7并尝试在Aptana3中构建我的Rails项目。我的Ruby是1.9.3。$gemin

  7. ruby - 可以正常中断的来自 Rake 的长时间运行的 shell 命令? - 2

    在几个项目中,我希望有一个类似rakeserver的rake任务,它将通过任何需要的方式开始为该应用程序提供服务。这是一个示例:task:serverdo%x{bundleexecrackup-p1234}end这行得通,但是当我准备停止它时,按Ctrl+c并没有正常关闭;它中断了Rake任务本身,它说rakeaborted!并给出堆栈跟踪。在某些情况下,我必须执行Ctrl+c两次。我可能可以用Signal.trap写一些东西来更优雅地中断它。有没有更简单的方法? 最佳答案 trap('SIGINT'){puts"Yourmessa

  8. ruby - 如何使用 ruby​​ mysql2 执行事务 - 2

    我已经开始使用mysql2gem。我试图弄清楚一些基本的事情——其中之一是如何明确地执行事务(对于批处理操作,比如多个INSERT/UPDATE查询)。在旧的ruby-mysql中,这是我的方法:client=Mysql.real_connect(...)inserts=["INSERTINTO...","UPDATE..WHEREid=..",#etc]client.autocommit(false)inserts.eachdo|ins|beginclient.query(ins)rescue#handleerrorsorabortentirelyendendclient.commi

  9. ruby - 引用具有指定索引的枚举器值 - 2

    假设我有一个可枚举对象enum,现在我想获取第三个项目。我知道一种通用方法是转换成数组,然后使用索引访问,如:enum.to_a[2]但这种方式会创建一个临时数组,效率可能很低。现在我使用:enum.each_with_index{|v,i|breakvifi==2}但这非常丑陋和多余。执行此操作最有效的方法是什么? 最佳答案 你可以使用take剥离前三个元素,然后剥离last从take给你的数组中获取第三个元素:third=enum.take(3).last如果您根本不想生成任何数组,那么也许:#Ifenumisn'tanEnum

  10. ruby - ruby 中的同一个程序如何接受来自用户的输入以及命令行参数 - 2

    我的ruby​​脚本从命令行参数获取某些输入。它检查是否缺少任何命令行参数,然后提示用户输入。但是我无法使用gets从用户那里获得输入。示例代码:test.rbname=""ARGV.eachdo|a|ifa.include?('-n')name=aputs"Argument:#{a}"endendifname==""puts"entername:"name=getsputsnameend运行脚本:rubytest.rbraghav-k错误结果:test.rb:6:in`gets':Nosuchfileordirectory-raghav-k(Errno::ENOENT)fromtes

随机推荐