Mysql索引相关学习笔记:B+ Tree、索引分类、索引优化、索引失效场景及其他常见面试题

前言

索引是Mysql中常用到的一个功能,可以大大加快查询速度,同时面试中也是经常碰到。本文是学习Mysql索引的归纳总结。

索引采用的数据结构——B+ 树

本部分主要是参考自小林Coding

B+树的由来

二分查找可以每次缩减一半,从而提高查找效率。

但是二分查找,若使用线性结构,每次插入,都是需要移动其余剩下的全部元素,消耗巨大。

因此有了二分查找树。

但是二叉树若每次插入的都比其父节点大,则会演变为链表,从而使查询复杂度从 O(logn)降低为 O(n)。

因此有了自平衡二叉树,诸如AVL树或红黑树,其都是这样的自平衡二叉树。

但由于其本质还是一棵二叉树,所以会随着数据量增大,导致层数增加, IO操作增多(每一层IO多一次)。

因此有了B树。其每个节点允许有M个子节点,M是B树的阶,假设M为3,那就是阶为3的B树,其每个节点最多有2(M-1)个数据和3(M)个子节点。若超过,则分裂节点。
在这里插入图片描述

但是 B 树的每个节点都包含数据(索引+记录),每次IO都会需要查询到节点上记录的内容。若数据量大于索引的大小,那么在读取底层节点索引的时候,就会导致较多的IO操作。从而使性能受到巨大影响。

因此有了B+ 树,B+树和B树的结构其实相似,只是仅将数据存储在底层叶子节点。其余的子节点仅存储索引。从而解决了数据大、影响IO的问题。
其次,其底层叶子节点之间,既存了索引也存了记录。叶子节点之间通过链表连接起来。从而对于范围查询,可以大大提升效率。

B+树的结构

关于B++树的结构看图就好了。
在这里插入图片描述
在这里插入图片描述

B+树的叶子节点是单链表还是双向链表

网上很多探讨针对于“其叶子节点是单向链表还是双向链表”,包括小林也是做出了一次纠正。
在此文发现了一些结论与有趣的探讨。

在这里插入图片描述

顺着此,找到了一个结论——B+ 树中各个页之间是通过双向链表连接的,叶子节点中的数据是通过单向链表连接的。

在这里插入图片描述

为什么选用了B+ 树

这里直接复制小林的结论了。

B+ 树 vs B 树

B+Tree 只在叶子节点存储数据,而 B 树 的非叶子节点也要存储数据,所以 B+Tree 的单个节点的数据量更小,在相同的磁盘 I/O 次数下,就能查询更多的节点。

另外,B+Tree 叶子节点采用的是双链表连接,适合 MySQL 中常见的基于范围的顺序查找,而 B 树无法做到这一点。

B+ 树 vs 二叉树

对于有 N 个叶子节点的 B+Tree,其搜索复杂度为O(logdN),其中 d 表示节点允许的最大子节点个数为 d 个。

在实际的应用当中, d 值是大于100的,这样就保证了,即使数据达到千万级别时,B+Tree 的高度依然维持在 3~4 层左右,也就是说一次数据查询操作只需要做 3~4 次的磁盘 I/O 操作就能查询到目标数据。

而二叉树的每个父节点的儿子节点个数只能是 2 个,意味着其搜索复杂度为 O(logN),这已经比 B+Tree 高出不少,因此二叉树检索到目标数据所经历的磁盘 I/O 次数要更多。

B+ 树 vs Hash

Hash 在做等值查询的时候效率贼快,搜索复杂度为 O(1)。

但是 Hash 表不适合做范围查询,它更适合做等值的查询,这也是 B+Tree 索引要比 Hash 表索引有着更广泛的适用场景的原因。

索引的分类

概述

按「数据结构」分类:B+tree索引、Hash索引、Full-text索引。

按「物理存储」分类:聚簇索引(主键索引)、二级索引(辅助索引)。

按「字段特性」分类:主键索引、唯一索引、普通索引、前缀索引。

按「字段个数」分类:单列索引、联合索引。

B+ Tree vs Hash vs Full-text

B+ Tree就是现在常用到的那样,详细见上文。

Hash在上文的最后一点也提到过,效率更快,但是不适合范围查询。其中InnoDB引擎不支持,只有Memory引擎可以使用。InnoDB引擎中,有“自适应哈希索引”。具体见此文。

Full-text索引是更罕见的,甚至于小林Coding都没有写…具体见此文。说一个适用场景:搜索引擎的全文搜索。

聚簇索引 vs 二级索引(辅助索引)

聚簇索引就是如上文B++ Tree中写的那样,放一起。

二级索引与之相对,叶子节点中存放的也仅仅是数据的位置。真正需要时候,再通过回表操作去查找。在聚簇索引之上所建立的索引,都叫做二级索引(辅助索引)

在这里插入图片描述

将数据存储于索引分开结构,索引结构的叶子节点指向了数据的对应行,myisam通过key_buffer把索引先缓存到内存中,当需要访问数据时(通过索引访问数据),在内存中直接搜索索引,然后通过索引找到磁盘相应数据,这也就是为什么索引不在key buffer命中时,速度慢的原因

这段对二级索引调用的描述感觉更加清晰。来源此文,里面也有相关更详细的讲解。

主键索引 vs 唯一索引 vs 普通索引 vs 前缀索引

· 主键索引:是在唯一索引的基础上又增加了不为空的约束(换言之,添加了唯一索引的字段,是可以包含NULL值的),即NOT NULL+UNIQUE,一张表里最多只有一个主键索引,当然一个主键索引中可以包含多个字段。

· 唯一索引:是在普通索引的基础上增加了数据唯一性的约束,一张表中可以同时存在多个唯一索引。

· 普通索引:是最基础的索引,这种索引没有任何的约束作用,它存在的主要意义就是提高查询效率。

· 前缀索引:前缀索引也叫局部索引,比如给身份证的前 10 位添加索引,类似这种给某列部分信息添加索引的方式叫做前缀索引。

单列索引 vs 联合索引

概念

单列索引:只在一个列上的索引被称作单列索引。一个表可以有多个单列索引,但这不是组合索引。

组合索引:两个或更多个列上的索引被称作组合索引,组合索引又叫联合索引。

在这里插入图片描述

最左前缀原则——按照最左优先的方式进行索引的匹配。

如果创建了一个 (a, b, c) 联合索引,如果查询条件是以下这几种,就可以匹配上联合索引:

where a=1;
where a=1 and b=2 and c=3;
where a=1 and b=2;
需要注意的是,因为有查询优化器,所以 a 字段在 where 子句的顺序并不重要。

但是,如果查询条件是以下这几种,因为不符合最左匹配原则,所以就无法匹配上联合索引,联合索引就会失效:

where b=2;
where c=3;
where b=2 and c=3;

因为(a, b, c) 联合索引,是先按 a 排序,在 a 相同的情况再按 b 排序,在 b 相同的情况再按 c 排序。所以,b 和 c 是全局无序,局部相对有序的,这样在没有遵循最左匹配原则的情况下,是无法利用到索引的。

索引优缺点(什么时候适合创建、不适合创建)

优缺点

优点——加快查询速度。

缺点:
1、需要占用物理空间,数量越大,占用空间越大。
2、创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增大。
3、会降低表的增删改的效率,因为每次增删改索引,B+ 树为了维护索引有序性,都需要进行动态维护。

是否创建

适合创建的场景

字段有唯一性限制的,比如商品编码;
经常用于 WHERE 查询条件的字段,这样能够提高整个表的查询速度,如果查询条件不是一个字段,可以建立联合索引。
经常用于 GROUP BY 和 ORDER BY 的字段,这样在查询的时候就不需要再去做一次排序了,因为我们都已经知道了建立索引之后在 B+Tree 中的记录都是排序好的。
⼤表中的关键列: 在⼤表中,如果查询的效率变得很低,可以考虑在关键列上创建索引。
表与表连接用于多表联合查询的约束条件的字段应当建立索引。

不适合创建的场景

⼩表: 对⼩表创建索引可能会带来额外的开销,因为在⼩数据集中扫描整个表可能⽐使⽤索引更快。

频繁的插⼊、更新和删除操作: 索引的维护成本会随着数据的插⼊、更新和删除操作⽽增加。如果表经常被修改,过多的索引可能会影响性能。

数据重复且分布平均的表字段:假如⼀个表有10万⾏记录,性别只有男和⼥两种值,且每个值的分布概率⼤约为50%,那么对这种字段建索引⼀般不会提⾼数据库的查询速度。MySQL 还有一个查询优化器,查询优化器发现某个值出现在表的数据行中的百分比很高的时候,它一般会忽略索引,进行全表扫描。

很少被查询的列: 如果某列很少被⽤于查询条件,那么为它创建索引可能没有明显的性能提升。

查询结果总⾏数较少的表: 如果查询的结果集总⾏数很少,使⽤索引可能不会有太⼤的性能提升

索引失效的情景

1、like %的模糊匹配。like %xx 或者 like %xx%会导致失效,like 'xx%'不会。原因是类似于姓名,根据首字母排序,但名字第二三个字的顺序没有关联。

2、对索引使用函数/表达式运算。因为索引中存储的是原始数据,而不是处理后的字段,所以不能走索引查询。

3、对索引隐式转换。因为隐式转换等同于用了函数。

4、联合索引的非最左匹配。详细见上方讲解处,就是类似于姓名排序是按照的首字母,后面的字母无关联。

5、where语句中or的多个条件,其中一个不是索引列。

在这里插入图片描述

索引优化

见此文

1)如果MySQL估计使用索引比全表扫描还慢,则不会使用索引。

2)前导模糊查询不能命中索引。

3)数据类型出现隐式转换的时候不会命中索引,特别是当列类型是字符串,一定要将字符常量值用引号引起来。

4)复合索引的情况下,查询条件不包含索引列最左边部分(不满足最左原则),不会命中符合索引。

5)union、in、or都能够命中索引,建议使用in。

6)用or分割开的条件,如果or前的条件中列有索引,而后面的列中没有索引,那么涉及到的索引都不会被用到。

7)负向条件查询不能使用索引,可以优化为in查询。
负向条件有:!=、<>、not in、not exists、not like等。

8)范围条件查询可以命中索引。范围条件有:<、<=、>、>=、between等。

9)利用覆盖索引进行查询,避免回表。
被查询的列,数据能从索引中取得,而不用通过行定位符row-locator再到row上获取,即“被查询列要被所建的索引覆盖”,这能够加速查询速度。

10)建立索引的列,不允许为null。
单列索引不存null值,复合索引不存全为null的值,如果列允许为null,可能会得到“不符合预期”的结果集,所以,请使用not null约束以及默认值。

部分面试题补充

此部分参考自此文。不得不说还是java社区资源多…

在这里插入图片描述

非聚簇索引一定会回表查询吗?

不一定。如果涉及到查询语句所要求的字段,全部命中了索引,那么就不必再进行回表查询。

举个简单的例子,假设我们在员工表的年龄上建立了索引,那么当进行select score from student where score > 90的查询时,在索引的叶子节点上,已经包含了score 信息,不会再次进行回表查询。

关于索引下推

此部分详细见此文

简单来说,(https://zhuanlan.zhihu.com/p/121084592)如果没有使用,那么流程是:检索到数据,返回Mysql服务器,判断是否符合。

如果使用了,则是:检索到数据,存储引擎判断是否符合,符合了再返回。

索引条件下推优化可以减少存储引擎查询基础表的次数,也可以减少MySQL服务器从存储引擎接收数据的次数。

为什么推荐使用自增主键作为索引?

结合B+Tree的特点,自增主键是连续的,在插入过程中尽量减少页分裂,即使要进行页分裂,也只会分裂很少一部分。并且能减少数据的移动,每次插入都是插入到最后。总之就是减少分裂和移动的频率。

参考资源

https://blog.csdn.net/qq_43592352/article/details/127351846

https://xiaolincoding.com/mysql/index/index_interview.html#%E6%8C%89%E5%AD%97%E6%AE%B5%E7%89%B9%E6%80%A7%E5%88%86%E7%B1%BB

https://mp.weixin.qq.com/s/lEx6iRRP3MbwJ82Xwp675w

https://tech.meituan.com/2014/06/30/mysql-index.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/347893.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【mongoDB】数据库的创建和删除

目录 1. 查看所有数据库 2.创建数据库 3.查看当前连接的数据库 4.删除数据库 1. 查看所有数据库 show dbs 2.创建数据库 use 数据库名 例如创建一个名为 aaa 的数据库 3.查看当前连接的数据库 db 4.删除数据库 use 数据库名 db.dropDataBase() 比如删除数据库 aaa

1.25号c++

1.引用 引用就是给变量起别名 格式&#xff1a; 数据类型 &引用名 同类型的变量名 &#xff08;& 引用符号&#xff09; eg: int a 10; int &b a; //b引用a,或者给a变量取个别名叫b int *p; //指针可以先定义 后指向 p &a; //int &a…

【MySQL】如何通过DDL去创建和修改员工信息表

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-fmKISDBsFq74ab2Z {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

docker(第二部分)

来自尚硅谷杨哥 少一点胡思乱想&#xff0c;心中无女人&#xff0c;编码自然神&#xff0c;忘掉心上人&#xff0c;抬手灭红尘。人间清醒&#xff0c;赚钱第一。好好学习&#xff0c;天天向上。听懂六六六。 7.Dokcer容器数据卷 1,&#xff09;坑&#xff1a;容器卷记得加入 …

shared_ptr 与 unique_ptr 的转换 笔记

推荐B站文章&#xff1a; 6.shared_ptr与unique_ptr_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV18B4y187uL?p6&vd_sourcea934d7fc6f47698a29dac90a922ba5a3我的往期文章&#xff1a; 独占指针&#xff1a;unique_ptr 与 函数调用-CSDN博客https://blog.csdn.n…

银行数据仓库体系实践(5)--数据转换

数据转换作业主要是指在数据仓库内的结构化数据批量加工&#xff0c;对于非结构化数据以及在线查询接口、数据流的开发主要是遵循代码开发规范以及各中间件的开发规范&#xff0c;如使用java来开发遵守java开发规范&#xff0c;使用Kafka需要遵循Kafka的使用和设计规范。同时做…

对话泛能网程路:能源产业互联网,行至中程

泛能网的能源产业互联网的标杆价值还不仅于此。其在产业互联之外&#xff0c;也更大的特殊性在于其也更在成为整个碳市场的“辅助运营商”&#xff0c;包括电力、碳等一系列被泛能网帮助企业改造和沉淀的要素资产&#xff0c;都在构成着碳交易市场的未来底层。 这恰是产业互联…

有关Quick BI中Case子句中多次使用lod函数返回空值问题分析

一、Quick BI中的lod_ include函数 lod_ include {维度1[,维度2]...:聚合表达式[:过滤条件]} 作用&#xff1a;将表达式中的维度一起作为分组依据进行订算。其中&#xff0c; 1) 维度1[,维度2]... &#xff1a;声明维度&#xff0c;指定聚合表达式要连接到的一个或多个维…

开源项目Git Commit规范与ChangeLog

一&#xff0c;conventional commit(约定式提交) Conventional Commits 是一种用于给提交信息增加人机可读含义的规范。它提供了一组用于创建清晰的提交历史的简单规则。 1.1 作用 自动化生成 CHANGELOG基于提交类型&#xff0c;自动决定语义化的版本变更向项目相关合作开发…

OpenCV书签 #互信息的原理与相似图片搜索实验

1. 介绍 互信息&#xff08;Mutual Information&#xff09; 是信息论中的一个概念&#xff0c;用于衡量两个随机变量之间的关联程度。在图像处理和计算机视觉中&#xff0c;互信息常被用来度量两幅图像之间的相似性。 互信息可以看成是一个随机变量中包含的关于另一个随机变…

【网站项目】基于SSM的251国外摇滚乐队交流和周边售卖系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

DAY30:回溯算法332\51\37基本思路了解+总结

Leetcode: 332 重新安排行程 代码随想录 这道题目有几个难点&#xff1a; 一个行程中&#xff0c;如果航班处理不好容易变成一个圈&#xff0c;成为死循环&#xff0c;容易出现环路。有多种解法&#xff0c;字母序靠前排在前面&#xff0c;让很多同学望而退步&#xff0c;如…

yolov8上使用gpu教程

yolov8上使用gpu教程 安装Cuda和Cudnnyolov8上使用gpu 安装Cuda和Cudnn 1.查看支持的cuda版本&#xff0c;并去官网下载。 nvidia-smi2.网址&#xff1a;https://developer.nvidia.com/cuda-toolkit-archive 3.安装细节 安装的前提基础是&#xff0c;有vs的C环境。我电脑有…

多流转换 (分流,合流,基于时间的合流——双流联结 )

目录 一&#xff0c;分流 1.实现分流 2.使用侧输出流 二&#xff0c;合流 1&#xff0c;联合 2&#xff0c;连接 三&#xff0c;基于时间的合流——双流联结 1&#xff0c;窗口联结 1.1 窗口联结的调用 1.2 窗口联结的处理流程 2&#xff0c;间隔联结 2.1 间隔联…

Qt单选按钮

前言 本篇文章介绍Qt的单选按钮&#xff0c;就是QRadioButton QRadioButton是一个选项按钮&#xff0c;可以打开&#xff08;选中&#xff09;或关闭&#xff08;取消选中&#xff09;。单选按钮通常向用户提供“众多之一”的选择。 在一组单选按钮中&#xff0c;一次只能选中…

手动搭建koa+ts项目框架(apidoc文档篇)

文章目录 一、安装apidoc工具二、使用1、项目根目录新建apidoc.json2、定义接口路由上方注解对应信息3、配置静态文件访问目录4、生成api文档如有启发&#xff0c;可点赞收藏哟~ 一、安装apidoc工具 全局安装 npm i apidoc -g查看是否安装成功 apidoc -v二、使用 1、项目根…

注解@profile的使用

目录 profile介绍配置演示 profile介绍 profile 通常作用在controller类上&#xff0c;当它标记的环境有效时&#xff0c;该controller类才生效&#xff0c;例如&#xff1a;Profile(“dev”),当dev环境被激活时&#xff0c;Profile(“dev”)所注解的controller类才生效。 配置…

工作软技能第一弹,关于职场沟通、成长的那些事

引言 在谈绩效后&#xff0c;我收获了一些心得&#xff0c;在此梳理出来&#xff0c;加深印象并且共勉 基本信息 在步入职场后&#xff0c;你可能跟我一样虽然技术水平有在上升&#xff0c;但是在处理一些事情上可能偶尔没能获得预期的成果。我在通过绩效沟通以及自我反思后…

【学网攻】 第(10)节 -- 路由器单臂路由配置

系列文章目录 目录 系列文章目录 文章目录 前言 一、单臂路由是什么&#xff1f; 二、实验 1.引入 实验拓扑图 PC配置 Sw配置 Router配置 实验验证 总结 文章目录 【学网攻】 第(1)节 -- 认识网络【学网攻】 第(2)节 -- 交换机认识及使用【学网攻】 第(3)节 -- 交…

Vue+OpenLayers7入门到实战:在地图上添加缩放控件、比例尺控件和鼠标经纬度位置显示控件

返回《Vue+OpenLayers7》专栏目录:Vue+OpenLayers7 前言 本章主要介绍如何使用OpenLayers7在地图上添加地图缩放控件,比例尺显示控件和鼠标经纬度位置展示控件这三个Control控件。 二、依赖和使用 "ol": "7.5.2"使用npm安装依赖npm install ol@7.5.…
最新文章