【MySQL】索引 (八)

news2025/2/26 3:02:23

🚗MySQL学习·第八站~
🚩本文已收录至专栏:MySQL通关路
❤️文末附全文思维导图,感谢各位点赞收藏支持~

一.引入

索引(index)是帮助MySQL高效获取数据的数据结构(有序)。数据库除了存储数据之外,还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据, 当我们在查找数据的时候,就可以在这些数据结构上实现高级查找算法,快速查找到我们想要的数据,这种数据结构就是索引

假如我们要执行一条查询SQL语句 : select * from user where age = 45;

  • 在无索引情况下
    在这里插入图片描述

在无索引的情况下,查询数据就需要从第一行开始扫描,一直扫描到最后一行,我们称之为全表扫描,性能很低

  • 在有索引情况下
    在这里插入图片描述

如果我们针对于这张表的age字段建立了索引,假设索引的数据结构就是二叉树(实际并不是,而是一种比二叉树更高效的数据结构),那么也就意味着,会对age这个字段建立一个二叉树的索引结构。此时我们在进行查询时,只需要扫描三次就可以找到数据了,极大的提高的查询的效率。

  • 当然使用索引也存在的优缺点,需要我们慎重选择
优势劣势
提高数据检索的效率,降低数据库的IO成本索引列也是要占用空间
通过索引列对数据进行排序,降低数据排序的成本,降低CPU的消耗索引大大提高了查询效率,同时却也降低更新表的速度, 如对表进行INSERT、UPDATE、DELETE时,效率降低。

二.数据结构

MySQL的索引是在存储引擎层实现的,不同的存储引擎有不同的索引结构,主要包含以下几种:

索引结构描述
B+Tree索引最常用的索引类型,大部分引擎都支持 B+ 树索引
Hash索引底层数据结构是用哈希表实现的, 只有精确匹配索引列的查询才有效, 不支持范围查询,也无法利用索引完成排序,但是查询效率较高。
R-tree(空间索 引)空间索引是MyISAM引擎的一个特殊索引类型,主要用于地理空间数据类 型,通常使用较少
Full-text(全文 索引)是一种通过建立倒排索引,快速匹配文档的方式。类似于 Lucene,Solr,ES

不同的存储引擎对于索引结构的支持情况也有所不同

索引InnoDBMyISAMMemory
B+tree索引支持支持支持
Hash 索引不支持不支持支持
R-tree 索引不支持支持不支持
Full-text支持支持不支持

我们平常所说的索引,如果没有特别指明,一般都是指B+树结构组织的索引。

特别说明:MySQL索引数据结构对经典的B+Tree进行了优化。在原B+Tree的基础上,增加了一个指向相邻叶子节点的链表指针,就形成了带有顺序指针的B+Tree,提高区间访问的性能,利于排序。
在这里插入图片描述

三.分类说明

在MySQL数据库中,将索引的具体类型主要分为以下几类:

分类含义特点关键字
主键索引针对于表中主键创建的索引默认自动创建, 只能有一个PRIMARY
唯一索引避免同一个表中某数据列中的值重复可以有多个UNIQUE
常规索引快速定位特定数据可以有多个
全文索引全文索引查找的是文本中的关键词,而不是比 较索引中的值可以有多个FULLTEXT

在InnoDB存储引擎中根据索引的存储形式,又可以分为以下两种:

分类含义特点
聚集索引(Clustered Index)数据存储与索引放到了一块,索引结构的叶子节点保存了行数据必须有,而且只有一个
二级(非聚集)索引(Secondary Index)数据与索引分开存储,索引结构的叶子节点关联的是对应的主键可以存在多个

聚集索引选取规则:

  • 如果存在主键,主键索引就是聚集索引。

  • 如果不存在主键,将使用第一个唯一(UNIQUE)索引作为聚集索引。

  • 如果表没有主键,或没有合适的唯一索引,则InnoDB会自动生成一个rowid作为隐藏的聚集索引
    在这里插入图片描述

  • 聚集索引的叶子节点下挂的是这一行的数据

  • 二级(非聚集)索引的叶子节点下挂的是该字段值对应的主键值
    在这里插入图片描述

当我们执行上述的SQL语句:

  • 由于是根据name字段进行查询,所以先根据name='Arm’到name字段的二级索引中进行匹配查找。但是在二级索引中只能查找到 Arm 对应的主键值 10。
  • 由于查询返回的数据是*,所以此时,还需要根据主键值10,到聚集索引中查找10对应的记录,最 终找到10对应的行row。
  • 最终拿到这一行的数据,直接返回即可。

这种先到二级索引中查找数据,找到主键值,然后再到聚集索引中根据主键值,获取数据的方式,就称之为回表查询。

由于存在回表查询,我们通过聚集索引查询值的方式要比通过二级索引查询值的方式快很多。因为走聚集索引,可以直接返回数据。 而走二级索引,需要先获取id值,然后再查询聚集索引获取值要慢许多。

四.相关操作

(1) 创建索引

  • 语法
CREATE [ UNIQUE | FULLTEXT ] INDEX 索引名 ON table_name (字段1,字段2,... );
  • 示例
-- 为用户表的姓名name字段创建名为idx_user_name的唯一索引
CREATE UNIQUE INDEX idx_user_name ON user(name);

-- 为用户表的手机号phone字段创建名为idx_user_phone的普通索引
CREATE INDEX idx_user_phone ON user(phone);

-- 为用户表的profession,age,status字段创建名为idx_user_pro_age_stae的联合索引
CREATE INDEX idx_user_pro_age_sta ON user(profession,age,status);

(2) 查看索引

  • 语法
SHOW  INDEX  FROM  表名;
  • 查看我们刚在创建的索引
    在这里插入图片描述

(3) 删除索引

  • 语法
DROP INDEX 索引名 ON 表名;
  • 删除name 索引,再次查看发现索引已删除
    在这里插入图片描述

五.索引失效情况

(1) 最左前缀法则

如果索引了多列(联合索引),要遵守最左前缀法则

最左前缀法指的是:查询会从索引的最左列开始,最左边的索引列必须存在,否则索引全部失效。并且不能跳过索引中的列。如果跳跃某一列,索引将会部分失效(后面的字段索引失效)。

  • 例如对于我们上述在 user 表中创建的联合索引,这个联合索引涉及到三个字段,顺序分别为:profession, age,status。 遵循最左前缀法指的是,查询时,最左变的索引列,也就是profession必须存在,否则索引全部失效。 而且中间不能遗漏某一列,否则该列后面的字段索引将失效,例如遗漏age列,status也会失效。

例如我们可以查看以下几种SQL的explain执行计划,可以发现索引有效

-- 全部存在,没问题
explain select * from user where profession = '软件工程' and age = 31 and status = '0';

-- 漏了status,其索引失效
explain select * from user where profession = '软件工程' and age = 31;

-- 漏了status,age,其索引失效
explain select * from user where profession = '软件工程';

-- 漏了age,其索引失效与status索引都失效
explain select * from user where profession = '软件工程' and status = '0';

-- 与编写的先后顺序无关,存在即可
explain select * from user where age = 31 and status = '0' and profession = '软件工程';

在这里插入图片描述

而我们遗漏了profession,即违背最左前缀法则将会导致索引失效

-- 失效
explain select * from user where age = 31 and status = '0';

-- 失效
explain select * from user where status = '0';

-- 失效
explain select * from user where age = 31;

在这里插入图片描述

(2) 范围查询

联合索引中,出现范围查询(>,<),范围查询右侧的列索引失效

  • 例如我们进行如下查询
explain select * from user where profession = '软件工程' and age > 30 and status = '0';

根据长度key_len我们可以知道:联合索引生效了,但是只有profession与age的索引生效了,status字段的索引没有生效。
在这里插入图片描述

值得注意的是:当范围查询使用>=<= 时,则不会产生影响。 因此,在业务允许的情况下,进行范围查询时,为了避免索引失效,我们可以使用类似于 >=<= 这类的范围查询,代替使用><
在这里插入图片描述

(3) 索引列运算

当我们在索引列上进行运算操作, 索引也将失效。

  • 例如我们对索引列进行函数运算,索引将失效
explain  select  *  from  user  where  substring(phone,10,2) = '15'

在这里插入图片描述

(4) 字符串不加引号

当我们对添加索引的字符串类型字段进行操作时,如果字符串不加引号,对于查询结果,没什么影响,但是数据库存在隐式类型转换,索引将失效

  • 例如 phone 为 varchar类型字段

在这里插入图片描述

(5) 模糊查询

如果仅仅是尾部模糊匹配,索引不会失效。如果是头部模糊匹配,索引失效

  • 我们发现,在like模糊查询中,在关键字后面加%,索引可以生效。而如果在关键字 前面加了%,索引将会失效
    在这里插入图片描述

(6) or连接条件

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

  • 例如我们先删除age字段上的联合索引,再进行or连接查询
    在这里插入图片描述

我们发现当or连接的条件,左右两侧字段都有索引时,索引才会生效~

(7) 数据分布影响

如果MySQL评估使用索引比全表扫描更慢,则不使用索引。

  • 例如,下面使用相同的SQL语句,只是传入的字段值不同,最终的执行计划也完全不一样
    在这里插入图片描述

这是因为MySQL在查询时,会评估使用索引的效率与走全表扫描的效率,如果走全表扫描更快,则放弃索引,走全表扫描。 因为索引是用来索引少量数据的,如果通过索引查询返回大批量的数据,则还不如走全表扫描来的快,此时索引就会失效。

六.使用优化

(1) SQL提示

当我们的字段存在多个索引时,MySQL会进行评估自动选择一个索引进行使用。我们也可以借助于SQL提示指定MySQL使用哪个索引

  • use index :建议MySQL使用哪一个索引完成此次查询(仅仅是建议,mysql内部还会再次进行评估,即或许不会遵从建议)
explain select * from 表名 use index(索引名) where 查询条件....;

在这里插入图片描述

  • ignore index :忽略指定的索引
explain select * from 表名 ignore index(索引名) where 查询条件....;

在这里插入图片描述

  • force index : 强制使用索引
explain select * from 表名 force index(索引名) where 查询条件....;

在这里插入图片描述

(2) 覆盖索引

在需求允许的情况下,尽量使用覆盖索引(查询使用了索引,并且需要返回的列,在该索引中已经全部能够找到),减少select *的使用。

例如我们使用age索引查询数据,如果只需要id,profession,age, status,那么我们可以直接写成select id,profession,age, status from user where profession = '软件工程' and age = 31 and status = '0' ,而不是select *.
在这里插入图片描述

从上述的执行计划我们可以看到,前面两天SQL的结果为 Using where; Using Index ; 而后面两条SQL的结果为: Using index condition

Extra含义
Using where; Using Index查找使用了索引,但是需要的数据都在索引列中能找到,所以不需 要回表查询数据
Using index condition查找使用了索引,但是需要回表查询数据

这里便牵涉到了我们上述所介绍的回表查询,我们在user表中创建了一个联合索引 idx_user_pro_age_sta,该索引关联了三个字段 profession、age、status,而这个索引也是一个二级索引,所以叶子节点下面挂的是这一行的主键id。 所以当我们查询返回的数据在 id、profession、age、status 之中,则直接走二级索引直接返回数据了。 如果超出这个范围,就需要拿到主键id,再去扫描聚集索引,再获取额外的数据 了,这个过程就是回表。 而我们如果一直使用select * 查询返回所有字段值,很容易就会造成回表查询(除非是根据主键查询,此时只会扫描聚集索引)。

  • 根据id查询,直接走聚集索引查询,一次索引扫描,直接返回数据,性能高。

在这里插入图片描述

  • 根据name字段查询,查询二级索引,但是由于查询返回在字段为 id,name,在name的二级索 引中,这两个值都是可以直接获取到的,因为覆盖索引,所以不需要回表查询,性能高。

在这里插入图片描述

  • 多查询一个gender字段,由于在name的二级索引中,不包含gender,所以,需要两次索引扫描,也就是需要回表查询,性能相 对较差一点。
    在这里插入图片描述

(3) 前缀索引

当字段类型为字符串(varchar,text,longtext等)时,有时候这些字段值会非常大(例如一段很长的文本),如果直接对此建立索引,这会让索引变得很大,查询时,浪费大量的磁盘IO, 影响查询效率。此时可以只将字符串的一部分前缀,建立索引,这样可以大大节约索引空间,从而提高索引效率

  • 创建语法
create index 索引名 on 表名(字段名(索引长度)) ;

在这里插入图片描述

有时候我们难以确定应该创建多长的索引,这时可以根据索引的选择性来决定。选择性是指不重复的索引值(基数)和数据表的记录总数的比值, 索引选择性越高则查询效率越高, 唯一索引的选择性是1,这是最好的索引选择性,性能也是最好的。

-- 可以直接计算比值
select  count(distinct 字段名) / count(*) from 表名;

-- 也可以使用函数截取部分数据进行计算
 select  count(distinct substring(字段名,开始位置,结束位置)) / count(*) from 表名;

在这里插入图片描述

  • 前缀索引的查询流程
    在这里插入图片描述

(4) 设计原则

  • 针对于数据量较大,且查询比较频繁的表建立索引。
  • 针对于常作为查询条件(where)、排序(order by)、分组(group by)操作的字段建立索引。
  • 尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高。
  • 如果是字符串类型的字段,字段的长度较长,可以针对于字段的特点,建立前缀索引
  • 在复合业务场景的情况下,尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间, 避免回表,提高查询效率。
  • 要控制索引的数量,索引并不是多多益善,索引越多,维护索引结构的代价也就越大,会影响增删改的效率
  • 如果索引列不能存储NULL值,请在创建表时使用NOT NULL约束它。当优化器知道每列是否包含 NULL值时,它可以更好地确定哪个索引最有效地用于查询

七.全文概览

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mot0Srm1-1690193674581)(C:\Users\15802\Pictures\mysql\索引\27.png)]

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

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

相关文章

Vue异步更新、$nextTick

需求&#xff1a;编辑标题, 编辑框自动聚焦 1. 点击编辑&#xff0c;显示编辑框 2. 让编辑框&#xff0c; 立刻获取焦点 this. isShowEdit true // 显示输入框 this . $refs . inp . focus () // 获取焦点 问题&#xff1a;"显示之后"&#xff0c;立刻获…

Bash编程

目录&#xff1a; bash编程语法bash脚本编写 1.bash编程语法 Bash 编程基础 变量引号数组控制语句函数 Bash 变量 语法&#xff1a; Variable_namevalue Bash 变量定义的规则 变量名区分大小写&#xff0c;a和A为两个不同的变量。变量名可以使用大小写字母混编的形式进行…

淘票猫影城系统-Spring Boot版

文章目录 一、引言TIPSticketcatticketcat-wechat-miniprogramticketcat-web-userticketcat-web-manager 三、项目截图wechat-miniprogramweb-userweb-manager 四、License 前往闪闪の小窝以获得更好的阅读和评论体验 一、引言 项目地址&#xff1a; 项目名项目内容项目地址开…

【Java】String类常用方法总结

文章目录 1丶boolean equals(Object anObject) 方法2丶int compareTo(String s) 方法3、 int compareToIgnoreCase(String str) 方法4丶字符串查找常用方法.5.丶字符串转化常用方法.大小写转换字符串转数组 6丶字符串替换7丶字符串拆分8丶字符串截取9丶去掉左右空格&#xff08…

备战秋招 | 笔试强训14

目录 一、选择题 二、编程题 三、选择题题解 四、编程题题解 一、选择题 1、下列有关this指针使用方法的叙述正确的是&#xff08;&#xff09; A. 保证基类保护成员在子类中可以被访问 B. 保证基类私有成员在子类中可以被访问 C. 保证基类共有成员在子类中可以被访问 D.…

机器学习 day31(baseline)

语音识别的Jtrain、Jcv和人工误差 对于逻辑回归问题&#xff0c;Jtrain和Jcv可以用分类错误的比例&#xff0c;这一方式来代替单单只看Jtrain&#xff0c;不好区分是否高偏差。可以再计算人类识别误差&#xff0c;即人工误差&#xff0c;作为基准线Jtrain与baseline对比只高了…

keepalived + lvs (服务端socket 客户端socket) udp协议

1、Keepalived 1. 1 keepalived 简介 1.1.1 什么是keepalived Keepalived一个基于VRRP 协议来实现的 LVS 服务高可用方案&#xff0c;可以利用其来解决单点故障。一个LVS服务会有2台服务器运行Keepalived&#xff0c;一台为主服务器&#xff08;MASTER&#xff09;&#xff…

MFC第二十二天 三种绘图句柄与三大坐标系(三大CDC派生类)简介以及应用、Invalidate刷新函数的功能和用法简介

文章目录 三种绘图句柄与三大坐标系&#xff08;三大CDC派生类&#xff09;简介以及应用三种HDC句柄三大CDC派生类什么是放泄露架构使用HDC句柄进行常见图形绘制演示 HPEN和HBRUSH句柄HPEN的创建 Invalidate刷新函数的功能和用法简介应用Win32下MFC下 附录 三种绘图句柄与三大坐…

【算法题解】51. 二叉树的最近公共祖先

这是一道 中等难度 的题 https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/ 题目 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个节点 p、q&#xff0c;最近公共祖先表示为…

Transformer+医学图像最新进展【2023】

Transformer主要用于自然语言处理领域。近年来,它在计算机视觉(CV)领域得到了广泛的应用。医学图像分析(MIA,Medical image analysis)作为机器视觉(CV,Computer Vision)的一个重要分支,也极大地受益于这一最先进的技术。 机构:新加坡国立大学机械工程系、中山大学智能系…

MySQL创建全文索引时,遇到“Temporary file write failure”的错误

MySQL创建全文索引时&#xff0c;遇到“Temporary file write failure”的错误 环境信息 MySQL Version: 8.0.28 engine: InnoDB rows: 100 index length: 10MB data length: 30MB 笔者在MYSQL上执行创建添加全文索引的语句&#xff1a;alter table users add fulltext index …

机器学习原理(1)集成学习基本方法

一.什么是集成学习 集成学习&#xff08;ensemble learning&#xff09;通过将多个学习器进行组合来完成学习任务。下图显示集成学习的一般结构&#xff08;取自周志华老师的西瓜书&#xff09;&#xff0c;个体学习器通常由一种现有的学习算法从训练数据产生&#xff0c;例如…

Vue项目实战失物招领

经过两天的时间&#xff0c;搞定了一个Vue版本的项目&#xff0c;在这里留下这两天的点点滴滴&#xff0c;这个项目主要实现了失物招领的相关功能&#xff0c;比如发布丢失信息&#xff0c;发布拾到信息&#xff0c;跑腿信息&#xff0c;用户注册&#xff0c;用户登录等相关功能…

故障分析 | Kubernetes 故障诊断流程

一、本文概述及主要术语 1.1 概述 本文基于 Pod 、Service 和 Ingress 三大模块进行划分&#xff0c;对于 Kubernetes 日常可能出现的故障问题&#xff0c;提供了较为具体的排查步骤&#xff0c;并附上相关解决方法或参考文献。 1.2 主要术语 Pod: Kubernetes 中创建和管理的…

Spring Boot日志:SLF4J和Logback

日志的分类 SpringBoot中的日志库分为两种&#xff1a; 实现库&#xff1a;提供具体的日志实现&#xff0c;例如日志级别的控制、打印格式、输出目标等。外观库&#xff1a;自身不提供日志实现&#xff0c;而是对其他日志库进行封装&#xff0c;从而方便使用。基于外观模式实…

接口自动化测试-Python+Requests+Pytest+YAML+Allure配套撸码(详细)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 接口自动化框架&a…

软件测试/测试开发丨Pytest测试框架学习笔记

Pytest 参数化用例 测试登录场景 测试登录成功&#xff0c;登录失败(账号错误&#xff0c;密码错误)*创建多种账号: 中⽂文账号&#xff0c;英⽂文账号*普通测试用例方法Copy 多份代码 or 读⼊入参数?*一次性执⾏多个输⼊入参数* def test_param_login_ok():# 登录成功user…

解决分类任务中数据倾斜问题

大家好&#xff0c;在处理文本分类任务时&#xff0c;基准测试流行的自然语言处理架构的性能是建立对可用选项的理解的重要步骤。在这里&#xff0c;本文将深入探讨与分类相关的最常见的挑战之一——数据倾斜。如果你曾经将机器学习&#xff08;ML&#xff09;应用于真实世界的…

selenium---滑动框验证码破解

前言 目前常见的验证码有很多种&#xff0c;比如数字验证码&#xff0c;滑动验证码&#xff0c;以及滑动补全图像验证码等&#xff0c;关于验证码的操作属于我们在UI自动化很大的一个障碍&#xff0c;今天安静来介绍下如何通过python来实现我们滑动验证码 滑动验证码 先来一…

MySQL之全文索引二三事

全文索引 MySQL全文索引是一种用于快速搜索文本字符串的索引&#xff0c;在MySQL数据库中&#xff0c;它可以用来提高文本搜索的效率。全文索引不同于普通索引&#xff0c;普通索引只是对列值进行排序&#xff0c;而全文索引则会对列的内容进行分词&#xff0c;并且对每个分词…