面试必须要知道的MySQL知识--索引

news2024/12/27 11:11:06

10 索引

10.1 数据页存储结构

10.1.1 数据页的各个部分

在讲索引之前,让我们看看一个单独的数据页是什么样子的

去除掉一些我们不太需要那么关注的部分后,简化如下:

也就是说平时我们在一个表里插入的一行一行的数据会存储在数据页里,然后数据页里的每一行数据都会按照主键大小进行排序存储,同时每一行数据都有指针指向下一行数据的位置,组成单向链表。

10.1.2 页分裂

随着业务的发生,我们的数据页一般会越来越大,当大到一定程度的时候,就需要再搞一个数据页了,如下图所示

但是这一步骤并不是说简简单单多加一个数据页就 OK,还需要保证新加的数据页中的每一行数据的主键值都要比前面的大才行,所以数据行有可能会在数据页中挪动。具体如下图所示:

10.2 索引页存储结构

10.2.1 概念

上一节我们讲了数据页的存储结构,这一节我们继续学习索引页的存储结构。

我们先思考一个问题,如果我们只有一般的数据页,咱们怎么找到自己想要的数据呢?是不是要将数据页全部遍历,再在每一个页中,通过二分查找查询数据。这么做,实在是太慢了!所以 MySQL 抽象出了一个索引页的概念,它和一般的数据页差不多,只不过存放的是最小主键值和页号。然后后续你查询主键值,就可以在目录里二分查找直接定位到那条数据所属的数据页,接着到数据页里二分查找定位那条数据就可以了,如下图所示

但是随着数据页越来越多,索引页也变得越来越多,这个时候怎么办呢?这个时候 MySQL 会抽象出一个更高层级的索引页,它里面记录的是最小主键值和索引页号。

那么现在问题再次来了,假如你最顶层的那个索引页里存放的下层索引页的页号也太多了,怎么办呢?此时可以再次分裂,再加一层索引,最后不断的向上加,索引页看起来就像下面这个样子了,也就是一颗 B+树。

10.2.1 例子

最后我们以最简单最基础的主键索引来举例,当你为一个表的主键建立起来索引之后,其实这个主键的索引就是一颗 B+树,然后当你要根据主键来查数据的时候,直接就是从 B+树的顶层开始二分查找,一层一层往下定位,最终一直定位到一个数据页里,在数据页内部的目录里二分查找,找到那条数据。

10.3 聚簇索引

10.3.1 特点

我们上面介绍的B+树索引,它有两个特点:

  • 使用记录主键值的大小进行记录和页的排序

  • B+树的叶子节点存储的是完整的用户记录

    符合这两个特点的索引,就是聚簇索引。在 InnoDB 存储引擎中,聚簇索引就是数据的存储方式,InnoDB 存储引擎会自动的为我们创建聚簇索引。

10.4 二级索引

10.4.1 概念

聚簇索引,使用记录主键值的大小进行记录和页的排序,他是和主键强关联的。但是如果查询的条件不是主键,而是其他列呢?这个时候,就要请出咱们的二级索引了。

二级索引也是一颗B+树,但是它的数据页里存放的是主键+目标字段值。换句话说,将聚簇索引中的主键值替换成目标值段,且叶子节点仅存储主键+目标字段值这两个列的值,那么他就是二级索引了。

当你要根据目标字段来查数据的时候,直接就是从 B+树的顶层开始二分查找,一层一层往下定位,最终一直定位到一个数据页里,在数据页内部的目录里二分查找,找到那条数据。但是这条数据只有主键+目标字段值。

10.4.2 图解

10.4.3 回表

如果你的查询结果中还需要有其他值,那么你得再根据主键在聚簇索引这个B+树中,再查找一次,得到最终的结果,这个过程叫做回表。

10.5 联合索引

联合索引也是一颗B+树,但是它的数据页里存放的是主键+多个目标字段值。其他和二级索引类似。

10.6 覆盖索引与回表查询

10.6.1 概念

首先我们要明确一点,覆盖索引,并不是真正的索引,他其实是一种基于索引的查询方式。

不管是二级索引,还是联合索引,如果你的查询结果中没有其他值,只有索引值,那么你得不需要再在聚簇索引这个B+树中,再查找一次,只需要扫描当前索引的叶子节点,就能得到结果,这种就叫做覆盖索引。

10.6.2 例子

select xx1,xx2,xx3 from table order by xx1,xx2,xx3

基于xx1,xx2,xx3建立联合索引

这种情况下,你仅仅需要联合索引里的几个字段的值,那么其实就只要扫描联合索引的索引树就可以了,不需要回表去聚簇索引里找其他字段了。

10.7 如何更好的建立索引

通过前文我们知道了索引其实是一颗一颗的B+树,那么接下来我们介绍一下B+树索引适用的条件。

10.7.1 索引适用的条件

首先我们给出一张示例表,如下:

CREATE TABLE `user` (  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',  `name` varchar(32) NOT NULL COMMENT '用户名',  `age` int(3) NOT NULL COMMENT '年龄',  PRIMARY KEY (`id`),  KEY `index_name_age` (`name`,`age`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='user示例表';

这个例子中,有两个索引,一个是根据id排序的聚簇索引,另一个是跟据name和age排序的二级索引。

注意:二级索引,是先跟据name排序,如果name相同,再根据age排序的。

10.7.1.1 全值匹配

例子:

SELECT * FROM user WHERE name = '第七人格' AND age = '29';

解析:

  • 因为B+树的数据页和记录先是按照name列的值进行排序的,所以先可以很快定位name列的值是“第七人格”的记录位置。

  • 在name列相同的记录里又是按照age列的值进行排序的,所以在name列的值是“第七人格”的记录里又可以快速定位age列的值是’29’的记录。

101.7.1.2 匹配左边的列

【例子】:

SELECT * FROM user WHERE name = '第七人格';

解析:

  • 因为B+树的数据页和记录先是按照name列的值进行排序的,所以先可以很快定位name列的值是“第七人格”的记录位置。

【反例】:

SELECT * FROM user WHERE age = '29';

解析:

  • 因为B+树的数据页和记录先是按照name列的值进行排序的,所以先可以很快定位name列的值是“第七人格”的记录位置,但是现在用age去找,你想想能找到吗?当然找不到了,你都没找到第一层排序的name值,怎么能找到下层的age呢?

10.7.1.3 匹配列前缀

【例子】:

SELECT * FROM user WHERE name like '第七%';

解析:

  • 因为B+树的数据页和记录先是按照name列的值进行排序的,那么的值是按照字符串排序的,字符串本质是按照字符排序的,这个例子中“第七”是被排好序了的,也可以很快定位name列的值是“第七…”的记录位置。

【反例】:

SELECT * FROM user WHERE name like '%第七%';

或者

SELECT * FROM user WHERE name like '%第七';

解析:

  • “第七”并没有排好序,所以无法使用索引。

10.7.1.4 匹配范围值

【例子】:

SELECT * FROM user WHERE name > 'Anna' AND name < 'Ziad';

解析:

  • name能用到索引。

【例子】:

SELECT * FROM user WHERE name > 'Anna' AND age < '35';

解析:

  • name能用到索引,age不能。

【思考】:

SELECT * FROM user WHERE name = 'Anna' AND age < '35';

请读者思考上面可以使用到索引吗?为什么?

10.7.1.5 排序

【例子】:

SELECT * FROM user ORDER BY name,age LIMIT 1;

解析:

  • 这个是可以用到索引的,因为他是按照联合索引的字段顺序去进行order by排序的,这样就可以直接利用联合索引树里的数据有序性,到索引树里直接按照字段值的顺序去获取数据。

【反例】:

SELECT * FROM user ORDER BY name ASC,age DESC;

解析:

  • 既有升序又有降序,没办法使用索引。

10.7.1.6 分组

【例子】:

SELECT name,age FROM user GROUP BY name , age;

解析:

  • 这个是可以用到索引的,原因可以类比排序。

10.7.2 阿里巴巴索引规约

  • 【强制】业务上具有唯一特性的字段,即使是组合字段,也必须建成唯一索引。

  • 【强制】超过三个表禁止 join。需要 join 的字段,数据类型保持绝对一致;多表关联查询时, 保证被关联的字段需要有索引。

  • 【强制】在 varchar 字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据 实际文本区分度决定索引长度。

  • 【强制】页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎来解决。

  • 【推荐】如果有 order by 的场景,请注意利用索引的有序性。order by 最后的字段是组合索引的一部分,并且放在索引组合顺序的最后,避免出现 file_sort 的情况,影响查询性能。

  • 【推荐】利用覆盖索引来进行查询操作,避免回表。

  • 【推荐】利用延迟关联或者子查询优化超多分页场景。

  • 【推荐】建组合索引的时候,区分度最高的在最左边。

以上规约摘自阿里巴巴开发手册,通过前面的学习,我相信大家可以从更深层次理解这些规约了,而不是一味的死记硬背。

10.8 执行计划与性能优化浅谈

10.8.1 总览

在生产中我们判断一个SQL写的好不好,一般都是通过EXPLAIN关键字,看他的执行计划的。

首先我们看看执行计划长什么样子,我们执行以下SQL

EXPLAIN SELECT * FROM user WHERE name = '第七人格' AND age = '29';

得到的执行计划如下:

10.8.2 要素

10.8.2.1 id

这个字段对性能优化来说,不太重要,我们只需要知道,在一个大的查询语句中每个SELECT关键字都对应一个唯一的id 就行了。

10.8.2.2 select_type

SELECT关键字对应的那个查询的类型,也不重要。

10.8.2.3 table

表名,意思就是查的哪个表,也不是很重要。

10.8.2.4 partitions

匹配的分区信息,我们接触不到这个知识点,99.9%都是null。

10.8.2.5 type

针对单表的访问方法,这个就非常重要了。

完整的类型如下:system,const,eq_ref,ref,fulltext,ref_or_null,index_merge,unique_subquery,index_subquery,range,index,ALL 。

这里我们针对比较常见和重要的几种类型介绍一下。

const,常量级,一般出现这个,就表示,你写的SQL非常好,性能非常快。哪些属于const呢?比如select * from user where id=x,或者select * from user where name=x这样的的语句,直接就可以通过聚簇索引或者二级索引+聚簇索引回表,轻松查到你要的数据。

值的一提的是,这里的二级索引必须是唯一索引。如果是普通索引,那么就是ref了,就如我们总览中的执行计划一样。当然,ref也是一种非常快的查询方式。

range也是一种常见的查询方式,一般出现在范围查询中,比如我们前面举的一个例子select * from user where name>=x and name <=x,假设name就是一个普通索引,此时就必然利用索引来进行范围筛选,一旦利用索引做了范围筛选,那么这种方式就是range。

我们再回忆一下这个sql,select name,age from user where age = ‘29’,因为age不是索引最左边的值,所以它是没法从联合索引的根节点二分查找快速跳转的,但是因为他的结果和条件都在索引里,所以MySQL的优化器,会直接扫描这个联合索引,一个个的遍历。也就是说,针对这种只要遍历二级索引就可以拿到你想要的数据,而不需要回源到聚簇索引的访问方式,就叫做index访问方式,这种访问方式相对于前面几种,就要慢的多。

最后再看看ALL,顾名思义,全表扫描,一般属于我们要杜绝的情况。

10.8.2.6 possible_keys

可能用到的索引。

10.8.2.7 key

实际上使用的索引。

10.8.2.8 key_len

实际使用到的索引长度。

10.8.2.9 ref

当使用索引列等值查询时,与索引列进行等值匹配的对象信息。

10.8.2.10 rows

预估的需要读取的记录条数,这个值按道理来说,越小越好。

10.8.2.11 filtered

某个表经过搜索条件过滤后剩余记录条数的百分比,对于单表查询来说,这个值没什么意义,都是100%,但是对于多表查询就有意义了,越小越好。

10.8.2.12 Extra

一些额外的信息。比如Using where,Using index,Using filesort等等。我们用group by、union、distinct之类的语法的时候,要是没法直接利用索引来进行分组聚合,那么MySQL会直接基于临时表来完成,会有大量的磁盘操作,也就是会使用文件排序(Using filesort)。这种情况一般也是需要避免的。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DDR-MIG 学习记录

MIG调试总结&#xff1a; 对vivado软件中用于控制DDR2 / DDR3 的 控制器MIG(Memory Interface Generator)IP核进行了仿真测试&#xff0c;以学习如何用IP核来控制FPGA板载SDRAM的读写。我们只需要学会MIG的接口控制就可以。 ①配置IP核 Xilinx 的 DDR 控制器的名称简写为 MIG&…

解密Long型数据传递:Spring Boot后台如何避免精度丢失问题

前端和后端之间的数据传递至关重要。然而&#xff0c;当涉及到Long类型数据时&#xff0c;可能会出现精度丢失问题&#xff0c;这会影响数据的准确性。本文将为你介绍两种解决方案&#xff0c;帮助你确保Long类型数据在前端和后端之间的精确传递。 精度丢失测试 访问:http://l…

深度学习可解释性Python库

本文整理了10个常用于可解释AI的Python库&#xff0c;方便我们更好的理解AI模型的决策。 原文阅读 什么是XAI&#xff1f; XAI&#xff08;Explainable AI&#xff09;的目标是为模型的行为和决策提供合理的解释&#xff0c;这有助于增加信任、提供问责制和模型决策的透明度…

SAP FB01 更新采购凭证历史EKBE

参考链接BAPI_ACC_DOCUMENT_POST – Vendor Down payment: Update Purchase order info and PO history 不需要链接里的替代过程&#xff0c;可以直接写在函数BAPI_ACC_DOCUMENT_POST的增强结构EXTENSION2里 需要复制BTE增强1050 在其中调用函数ME_CREATE_HISTORY_FINANCE 即…

工具 | docker删除不使用的容器

工具 | docker删除不使用的容器 Docker 清理命令

ESP32-Web-Server 实战编程-通过网页控制设备的 GPIO

ESP32-Web-Server 实战编程-通过网页控制设备的 GPIO 概述 前述博客讲解了 Web 编程的基本知识&#xff0c;包括 HTML、CSS、JavaScript 三个部分&#xff0c;从这节开始&#xff0c;我们进入实战部分&#xff0c;在实际项目中进一步学习 ESP32-Web 编程。 GPIO &#xff08…

产品解读:GreatADM如何快速改造单实例为双主、MGR、读写分离架构?

前言 单机GreatDB/GreatSQL/MySQL将架构调整为多副本复制的好处有哪些&#xff1f;为什么要调整&#xff1f; 性能优化&#xff1a;如果单个GreatDB服务器的处理能力达到瓶颈&#xff0c;可能需要通过主从复制、双主复制或MGR及其他高可用方案来提高整体性能。通过将读请求分发…

免交互语法expect

目录 前瞻 相关命令 范例一&#xff1a;免密登录另外一台主机并创建用户 范例二&#xff1a;免密登录另外三台主机并创建用户 前瞻 expect是建立在tcl&#xff08;tool command language&#xff09;语言基础上的一个工具&#xff0c;常被用于进行自动化控制和测试&#xf…

前后端分离开发出现的跨域问题

先说说什么是跨域。 请求的URL地址中的协议、域名、端口号中的任意一个与当前URL不同就是跨域。 比如&#xff1a; 当前页面的URL请求的URL是否跨域原因htttp://localhost:8080htttps://localhost:8080是协议不同htttp://localhostll:8080htttp://localhost:8080是域名不同htt…

校园跑腿的核心功能

校园跑腿是指在校园内提供各种代办和服务的便利服务。 1. 快速送货&#xff1a;校园跑腿可以提供快速的送货服务&#xff0c;包括食品、快递、文件等物品的送达。 2. 打印复印&#xff1a;校园跑腿可以提供打印、复印等文档处理服务&#xff0c;方便学生和教职工处理各种文档…

Glide结合OkHttp保证短信验证接口携带图形验证码接口返回Cookie值去做网络请求

一、实现效果 二、步骤 注意&#xff1a;仅展示核心部分代码 1、导入依赖 api com.github.bumptech.glide:glide:4.10.0 kapt com.github.bumptech.glide:compiler:4.10.0 api com.squareup.okhttp3:okhttp:3.11.0 api com.squareup.okhttp3:logging-interceptor:3.11.02、自…

【Web】BJDCTF 2020 个人复现

目录 ①easy_md5 ②ZJCTF&#xff0c;不过如此 ③Cookie is so subtle! ④Ezphp ⑤The Mystery of IP ①easy_md5 ffifdyop绕过SQL注入 sql注入&#xff1a;md5($password,true) 右键查看源码 数组绕过 ?a[]1&b[]2 跳转到levell14.php 同样是数组绕过 param1[…

C语言第三十六弹--实现转移表的多种方法

使用C语言通过多种方法实现转移表 方法一、普通法 思路&#xff1a;如图实现多种操作&#xff0c;首先创建菜单&#xff0c;需要运行一次再判断条件&#xff0c;所以通过do{}while(); 循环来实现多次。有多种选择&#xff0c;使用switch case选择语句&#xff0c;再在对应case…

蓝桥杯第229题 迷宫与陷阱 BFS C++ 模拟 带你理解迷宫的深奥

题目 迷宫与陷阱 - 蓝桥云课 (lanqiao.cn)https://www.lanqiao.cn/problems/229/learning/?page1&first_category_id1&name%E8%BF%B7%E5%AE%AB%E4%B8%8E%E9%99%B7%E9%98%B1 思路和解题方法 首先&#xff0c;定义了一个结构体node来表示迷宫中的每个节点&#xff0c;包…

计算机丢失vcomp140.dll是什么意思,如何解决与修复(附教程)

vcomp140.dll缺失的5种解决方法以及vcomp140.dll缺失原因 引言&#xff1a; 在日常使用电脑的过程中&#xff0c;我们可能会遇到一些错误提示&#xff0c;其中之一就是“vcomp140.dll缺失”。这个错误提示通常出现在运行某些程序或游戏时&#xff0c;给使用者带来了困扰。本文…

Java数据结构之优先级队列(PriorityQueue)

1、概念 队列&#xff1a;是一种FIFO&#xff08;First-In-First-Out&#xff09;先进先出的数据结构&#xff0c;对应于生活中的排队的场景&#xff0c; 排在前面的人总是先通过&#xff0c;依次进行。 优先队列&#xff1a;是特殊的队列&#xff0c;从“优先”一词&#xff…

免调试计量表,4G无线电表,可以远程抄表,安科瑞ADW300一款全能实现?

1.概述 ADW300 无线计量仪表主要用于计量低压网络的三相有功电能&#xff0c;具有体积小、精度高、功能丰富等优点&#xff0c;并 且可选通讯方式多&#xff0c;可支持 RS485 通讯和 Lora、NB、4G、wifi 等无线通讯方式&#xff0c;增加了外置互感器的电流采样 模式&#xff0…

计算机毕业设计 基于PHP的考研互助交流系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

设备管理的方法与思路

阅读本文你将了解设备管理的思路与方法&#xff1a;一、制定全面的管理计划&#xff1b;二、标准化管理流程&#xff1b;三、设备维护与保养&#xff1b;四、风险管理与预防&#xff1b;五、引入数字化工具。 设备管理在生产制造领域是保障生产安全和效率的核心环节。通过引入…

【c++|SDL】开始使用之---demo

every blog every motto: You can do more than you think. https://blog.csdn.net/weixin_39190382?typeblog 0. 前言 SDL 记录 1. hello word #include<SDL2/SDL.h>SDL_Window* g_pWindow 0; SDL_Renderer* g_pRenderer 0;int main(int argc, char* args[]) {//…