MySql 索引失效、回表解析

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云解析 DNS,旗舰版 1个月
简介: MySql 索引失效、回表解析

前言



该篇内容:


结合实例,介绍常见的几种索引失效场景,以及对每个场景会做一些额外的扩展说明.

后面写着写着跑题了,为了想给大家讲下什么是回表...然后。。。。


正文



失效 一



查询的字段列未添加索引


ps:这...直接从失效二开始看吧,我承认我在啰嗦。


请看示例,表内 userProfession 列 存入的是人员的职业信息 :


image.png

该字段列未使用索引,所以查询无法命中索引 :


EXPLAIN SELECT * FROM userinfo WHERE userProfession='教师';


分析结果:


image.png

失效 二



建索引的字段 类型为   varchar , 但是 查询的 传入值 没有使用   ‘ ’ ,即没加引号。

请看示例,表内 userCardNum 列 存入的是职工的工号 :


image.png


userCardNum 设置的是varchar 类型   :


image.png


给  userCardNum 添加了唯一索引 :


image.png


正常命中索引查询SQL语句分析(使用 EXPLAIN ):


 EXPLAIN SELECT * FROM userinfo WHERE userCardNum= '10011';


索引命中分析结果:


image.png

索引失效,传入值没有带  ‘  ’ 单引号:


 EXPLAIN SELECT * FROM userinfo WHERE userCardNum= 10011;


索引失效分析结果:


image.png

切记: 传入的值使用方式记得跟数据库表内列,索引设置字段保持一样的类型,这样万无一失。


扩展补充,为什么失效二情况 强调了 索引字段是 varchar ,传入 值使用不加引号 呢?


因为一部分人在理解这种情况 有错误的思想,理解为 涉及类型转换 ,以为是因为单纯的字段类型不对应 导致索引失效,这里必须补充一下一个示例:


字段列 userAge:


image.png


userAge类型为 int :


image.png


给  userAge添加了索引 :


image.png


SQL使用传入值,添加了引号 :


EXPLAIN SELECT * FROM userinfo WHERE userAge  = '25';


结果分析 ,可以命中索引:


image.png


所以,咱们记住,这种失效场景是,数据库表内字段是varchar,给这字段添加了索引,传入值sql未使用引号,这时候涉及隐式转换,才会导致索引失效。 当然这也是为什么我让大家切记,保持与表内数据类型一致,这不管是啥都很稳妥。


失效三  



使用 like 进行 左模糊匹配查找  ‘%XXX’

请看示例,表内字段列 userName


image.png



给userName 添加索引:


image.png


索引失效 ,使用LIKE 并使用的是左匹配(同样左右一起用也是失效的):


EXPLAIN SELECT * FROM userinfo WHERE userName LIKE '%一';


索引失效分析结果:


image.png

扩展补充,当使用LIKE ,索引就必然失效么?


并不是,这里强调了 左匹配。


请看 LIKE 右匹配:


EXPLAIN SELECT * FROM userinfo WHERE userName LIKE '王%';


索引命中分析结果:


image.png

失效 四



索引字段作为查询条件时,使用了计算或者函数


请看示例SQL ,索引字段使用了计算:


EXPLAIN SELECT * FROM userinfo WHERE userAge  +2= 37;


索引字段因使用计算,失效分析结果:


image.png


再看示例,索引字段使用函数:


EXPLAIN SELECT * FROM userinfo WHERE  TRIM(userName) = '陈七';


索引字段因使用函数,失效分析结果:


image.png

失效 五



使用 OR ,条件字段中包含有未设索引字段列


请看示例,表内userProfession字段没有添加索引, 而 userAge添加了索引:


image.png


执行SQL使用OR ,同时使用userProfession ,userAge作为条件查找:


  EXPLAIN SELECT * FROM userinfo WHERE userProfession='教师' OR  userAge  = 25;


索引未命中分析结果:


image.png

扩展补充,


如果 使用 OR ,作为查找条件的字段都已经添加了索引 ,会是什么情况?


例如 userAge 我们使用了索引,


  EXPLAIN SELECT * FROM userinfo WHERE userAge  = 23 OR  userAge  = 35;


这样会命中索引么?


注意了,分情况,因为我们的userAge添加的不是唯一索引,因为年龄嘛,总会有重复:


再看当前数据,可以看的 userAge 为 35 ,userAge为 23 的 都只有一条数据,也就是对应目前表内数据,其实是唯一数据:


image.png

这时候,索引分析结果,索引命中了:


image.png


可以看的,索引命中了。


那么接着,我们把一个userAge查找条件换成25, 数据表内数据 25 的有两条,不唯一:


EXPLAIN SELECT * FROM userinfo WHERE userAge  = 25 OR  userAge  = 35;


这时候,索引分析结果,索引失效了:


image.png


ps: 也就是,若把索引设置成为唯一索引,那么数据库内也就不存在重复数据了,这时候如果使用or 查询同个索引字段列,那么就是命中的。当时往往有时候,就是类似文中的情况。userAge就是设置为不唯一索引,那么就是使用 UNION ALL 去解决或者从代码层面分开查询。


配上使用 UNION ALL的方式:


EXPLAIN 
SELECT * FROM userinfo WHERE userAge  = 25
UNION ALL
SELECT * FROM userinfo WHERE userAge  = 35


索引分析结果,是命中的:


image.png


失效 六



联合索引,不满足最佳左前缀原则,导致索引失效


请看示例,表内 userWeight 、userHeight、userSight 三个字段:


image.png


给 userWeight 、userHeight、userSight 这三个字段建立联合索引 :

image.png


注意顺序,最左为 userWeight


这时候,如果SQL 在使用这些字段索引查找时,先看单个字段查找:


单个使用userWeight :


EXPLAIN SELECT * FROM userinfo WHERE  userWeight='50';


索引分析结果,索引命中,因为满足了最佳做前缀原则:


image.png


那么我们换成单个使用 userHeight,


EXPLAIN   SELECT * FROM userinfo WHERE  userHeight='180' ;


索引分析结果,索引失效了:


image.png

同样换成 userSight 也是一样,索引失效了,因为这种情形就是没有满足最佳做前缀原则。


对于使用联合索引,还没完。


当我们同时使用联合索引里面的2个或2个以上的字段列时:


使用 userWeight 和 userSight:


  EXPLAIN SELECT * FROM userinfo WHERE  userWeight='50' and userSight='5.2';


索引分析结果,索引命中(因为 userWeight=‘50’ ,满足了最佳左前缀原则):


image.png

那么如果我们把这两个条件 换下前后顺序呢?


  EXPLAIN SELECT * FROM userinfo WHERE userSight='5.2' AND userWeight='50';


索引分析结果,索引命中:


image.png

这是特意补充提一下的,这个最佳左前缀原则是对于建立的联合索引里面字段的顺序最左而言,不是sql语句写的条件顺序。


那么如果我们使用的是 userHeight 和 userSight 呢?


  EXPLAIN SELECT * FROM userinfo WHERE  userHeight='180' and userSight='5.2';


这个不做解释,连最左的边都没粘上,还想命中索引?  怎么敢的。


失效 七



使用了 is not null  、 is null ,索引不生效


前排说明,这个失效场景并不是如表述所言!情况以下分析!


请看示例表数据,里面userName里面,包含了一条数据为NULL的情况:


image.png


然后SQL使用了 is not  null :


EXPLAIN SELECT * FROM userinfo WHERE userName is not null;


索引分析结果,索引未命中:


image.png

那么SQL使用了 is null:


EXPLAIN SELECT * FROM userinfo WHERE userName is  null;


索引分析结果,索引命中:


image.png

为什么,为什么索引命中了?  不是说使用了 is null 、is not null 会失效么?


这段话摘自mysql官方文档,is null 不会影响索引的使用:

MySQL can perform the same optimization on col_name IS NULL that it can use for col_name = constant_value. For example, MySQL can use indexes and ranges to search for NULL with IS NULL.


那可能有很多看官,确实遇到了使用is null 失效的问题,就会很疑惑。


是玄学么? 并不是。


这就是本文想补充的一种索引失效的场景:


当执行的sql语句,mysql认为扫描全表都比使用索引快的时候,那么索引就不会被使用!


也就是mysql会去计算查询成本,那个成本低就选择哪种方式。


PS: 接下来我跑题了, 非常啰嗦,我跑出了 回表,聚集索引 ,非 聚集索引,索引覆盖 这些不符合文章主题的内容。不想阅读的看官可以点个赞就走了。


ok,继续回到跑题,那啥时候mysql才会有这种认为呢?


通常mysql有这种想法的时候,大多数情况是因为该sql 查询中回表数量太多。


那么引申出一个概念,回表。

什么是回表(跑题,但是无所谓了)?


想深入了解的看官,可以去摸索深入一下,这里我用我的小白文给大家简单讲一讲。


结合实例讲解(对了,该篇文章都是基于引擎InnoDB的):


假如咱们现在有一张表,里面有   id (主键),userName(索引),userPorfession (无索引)


image.png

首先为了更好地解释回表, 我逼不得已又得引出两个 新概念   聚集索引 和 非 聚集索引 。


(哈哈麻烦了,感觉跑题越跑越远了,无所谓了)


聚集索引 :


通常来说,就是咱们表的主键。


那如果这张表没有主键,那么第一个创建的唯一非空索引,就是该表的聚集索引 。


那么你说,又没主键,又没创建唯一非空索引,我明白,你想搞事。 但是mysql不会被你搞,这种情况mysql会隐式地为该表创建一个聚集索引 ,具体是啥,创建规则,我就不细说了。(因为对于我来说,我不想看到这种情况出现,就算没必要很多时候我也会去建一个主键id作为伪列。)


好了,聚集索引  我们已经了解它的由来。


那么它的作用:


简单一点来说,它就是这表数据的老大,只要命中这个家伙,其他字段它都能给你找齐,也就是说这个家伙是指向了整行数据的。


非聚集索引 :


其他索引,类似这个表里,userName的索引 就是 非聚集索引 。


这个家伙的作用:


你找它,它只能帮你找到它的老大 聚集索引(主键),也就是这个家伙是指向聚集索引的。


ok,讲到这里,回到我们的表示例,讲讲啥是回表场景:


id (主键),userName(索引),userPorfession (无索引)


image.png

执行SQL:


SELECT id , userName, userProfession  FROM userinfo  WHERE id  = 7;


执行计划分析:


image.png


这时候,索引命中的是id 主键 。


没错,命中了老大, 不会回表。因为在老大的索引树里面,啥玩意都能给你找齐了。


再看执行SQL:


SELECT id , userName, userProfession FROM userinfo WHERE userName  = '刘二';


执行计划分析:


image.png


这时候,命中的不是老大,是一个 非聚集索引 ,  这时候需要回表。


为什么啊? 因为我们使用的是select * ,意思是我们还得查找 userPorfession  字段数据。


那么现在命中了userName 的索引 nameIndex,它还能帮我们找到老大 id,但是它无法帮我们直接找到 userPorfession  。


其实这里涉及到一个概念,叫 索引覆盖 。


什么是索引覆盖? (不能再跑题了,这里我就提一句吧,就是从索引树里面指向的数据字段里已经包含了select  xx,xxx 这些字段,那么就是索引数据已经够用了,没必要回表查额外的数据了。)


快速看图了解:

image.png

执行分析结果 :


image.png


回归刚刚讲到的,userName ,id 我们都能找到,但是为了找 userPorfession  ,我们只能在找到id之后,再根据id再去找一遍主键的索引树数据,找出与id绑定的userPorfession,这种情形就是 回表    。


什么叫回表?好的这里简单讲述完毕。


那又又又回到我们最早提到的问题,


mysql认为扫描全表都比使用索引快的时候,那么索引就不会被使用。


而通常mysql有这种想法的时候,大多数情况是因为该sql 查询中回表数量太多。


那么怎么尽可能避免这种情形呢?


刚刚已经讲了回表是啥原因导致的了,那么为了尽可能避免这种情形,那就是:


1.使用聚集索引 也就是主键进行查找


2. select 查找的字段列 被 命中的索引的索引树里的数据 包含,也就是索引覆盖。


3.升级索引


1.2都看懂了。3是什么意思呢?


就是说针对某些场景,例如目前SQL:


SELECT id , userName, userProfession FROM userName  = '刘二';


因为目前id有主键索引,userName有索引,但是 userProfession没索引导致需要回表。


那么我们把userName的单索引升级为 联合索引 (userName,userProfession)。


好吧,该篇就到此。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
22天前
|
数据库 索引
深入探索数据库索引技术:回表与索引下推解析
【10月更文挑战第15天】在数据库查询优化的领域中,回表和索引下推是两个核心概念,它们对于提高查询性能至关重要。本文将详细解释这两个术语,并探讨它们在数据库操作中的作用和影响。
43 3
|
9天前
|
监控 关系型数据库 MySQL
MySQL自增ID耗尽应对策略:技术解决方案全解析
在数据库管理中,MySQL的自增ID(AUTO_INCREMENT)属性为表中的每一行提供了一个唯一的标识符。然而,当自增ID达到其最大值时,如何处理这一情况成为了数据库管理员和开发者必须面对的问题。本文将探讨MySQL自增ID耗尽的原因、影响以及有效的应对策略。
32 3
|
10天前
|
存储 关系型数据库 MySQL
MySQL 字段类型深度解析:VARCHAR(50) 与 VARCHAR(500) 的差异
在MySQL数据库中,`VARCHAR`类型是一种非常灵活的字符串存储类型,它允许存储可变长度的字符串。然而,`VARCHAR(50)`和`VARCHAR(500)`之间的差异不仅仅是长度的不同,它们在存储效率、性能和使用场景上也有所不同。本文将深入探讨这两种字段类型的区别及其对数据库设计的影响。
23 2
|
14天前
|
存储 关系型数据库 MySQL
PHP与MySQL动态网站开发深度解析####
本文作为技术性文章,深入探讨了PHP与MySQL结合在动态网站开发中的应用实践,从环境搭建到具体案例实现,旨在为开发者提供一套详尽的实战指南。不同于常规摘要仅概述内容,本文将以“手把手”的教学方式,引导读者逐步构建一个功能完备的动态网站,涵盖前端用户界面设计、后端逻辑处理及数据库高效管理等关键环节,确保读者能够全面掌握PHP与MySQL在动态网站开发中的精髓。 ####
|
18天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第27天】本文深入探讨了MySQL的索引策略和查询性能调优技巧。通过介绍B-Tree索引、哈希索引和全文索引等不同类型,以及如何创建和维护索引,结合实战案例分析查询执行计划,帮助读者掌握提升查询性能的方法。定期优化索引和调整查询语句是提高数据库性能的关键。
85 1
|
22天前
|
存储 关系型数据库 MySQL
MySQL MVCC深度解析:掌握并发控制的艺术
【10月更文挑战第23天】 在数据库领域,MVCC(Multi-Version Concurrency Control,多版本并发控制)是一种重要的并发控制机制,它允许多个事务并发执行而不产生冲突。MySQL作为广泛使用的数据库系统,其InnoDB存储引擎就采用了MVCC来处理事务。本文将深入探讨MySQL中的MVCC机制,帮助你在面试中自信应对相关问题。
70 3
|
19天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第26天】数据库作为现代应用系统的核心组件,其性能优化至关重要。本文主要探讨MySQL的索引策略与查询性能调优。通过合理创建索引(如B-Tree、复合索引)和优化查询语句(如使用EXPLAIN、优化分页查询),可以显著提升数据库的响应速度和稳定性。实践中还需定期审查慢查询日志,持续优化性能。
47 0
|
9天前
|
SQL 关系型数据库 MySQL
12 PHP配置数据库MySQL
路老师分享了PHP操作MySQL数据库的方法,包括安装并连接MySQL服务器、选择数据库、执行SQL语句(如插入、更新、删除和查询),以及将结果集返回到数组。通过具体示例代码,详细介绍了每一步的操作流程,帮助读者快速入门PHP与MySQL的交互。
24 1
|
11天前
|
SQL 关系型数据库 MySQL
go语言数据库中mysql驱动安装
【11月更文挑战第2天】
26 4
|
1月前
|
存储 关系型数据库 MySQL
Mysql(4)—数据库索引
数据库索引是用于提高数据检索效率的数据结构,类似于书籍中的索引。它允许用户快速找到数据,而无需扫描整个表。MySQL中的索引可以显著提升查询速度,使数据库操作更加高效。索引的发展经历了从无索引、简单索引到B-树、哈希索引、位图索引、全文索引等多个阶段。
61 3
Mysql(4)—数据库索引

推荐镜像

更多