索引怎么又失效了?

索引失效的案例

导语

建立索引可以提高查询数据的速度,但有时候建完索引并没有达到预期的效果,索引没有被使用,仍然走了全表扫描。下文将通过一些案例分析索引失效的情况。

前置知识

B+Tree 索引结构

B+Tree中,非叶子节点存放索引,叶子节点存放数据。每个节点按页存储,叶子节点之间用双链表连接。示意图如下:

聚集索引 VS 二级索引

聚集索引也叫一级索引、聚簇索引、主键索引,是对表中的主键创建的索引,叶子节点存放的是行数据。

对表中的非主键字段创建索引,创建出来的是二级索引,二级索引的叶子节点存放主键值,如果从二级索引中查不到需要的信息,就会拿着主键值去聚集索引里查,这个过程叫回表查询。

回表查询

例如现在有一张表:student(id, stuno, name, age, height, score),主键是 id,对name字段建立索引,执行如下语句会出现回表查询:

sql 复制代码
select * from student where name = 'Jhon';

回表查询的过程:从二级索引取到 id 值,再去聚集索引里查行数据。

索引失效案例分析

以下案例基于MySQL 8,InnoDB 存储引擎,B+Tree索引

1、联合索引未遵循最左匹配原则

表结构:student(id, stuno, name, age, height, score),(age、height、score均为int类型)。对 age、height、score 建立联合索引:

sql 复制代码
create index idx_ahs on student(age, height, score);

分析如下查询语句:

索引未失效

where age = 15;

sql 复制代码
explain select * from student where age = 15;

where age = 15 and height = 158;

sql 复制代码
explain select * from student where age = 15 and height = 158;

where age = 15 and score = 90; 跳过了中间的 height 字段,索引下推

sql 复制代码
explain select * from student where age = 15 and score = 90;

where age = 15 and height = 158 and score = 90;

sql 复制代码
explain select * from student where age = 15 and height = 158 and score = 90;

调换顺序 依然可以生效:where score = 90 and height = 158 and age = 15;

sql 复制代码
explain select * from student where score = 90 and height = 158 and age = 15;

范围查询

where age > 15 and height = 158;

where age >= 15 and height = 158;

sql 复制代码
explain select * from student where age>15 and height=158;
sql 复制代码
explain select * from student where age>=15 and height=158;

索引失效,未遵循最左匹配

where height = 158;

where height = 158 and score = 90;

sql 复制代码
explain select * from student where height = 158;
explain select * from student where height = 158 and score = 90;

分析

在联合索引(a,b,c)中,先根据 a 排序,a 相同时再根据 b 排序,b相同时再根据 c 排序。所以对于全体 a 而言是有序的,对于 b 来说,只在 a 相同的时候才有序,从整体上看 b 是无序的,c 类似。

因此,查询时如果跳过 a ,直接根据 b 查,会走全表扫描,因为 b 整体上是无序的。

2、模糊匹配 like '%XXX'

对 student 表的 name 字段建立普通索引:

sql 复制代码
create index idx_name on student(name);

使用左模糊匹配会失效

where name like '%k';

where name like '%o%';

sql 复制代码
explain select * from student where name like '%k';
explain select * from student where name like '%o%';

3、对索引使用函数或表达式运算

where length(name) = 4;

sql 复制代码
explain select * from student where length(name)  =4;

where id + 1 = 3;

sql 复制代码
explain select * from student where id + 1 = 3;

这样索引不会失效:where id = 3 - 1;

sql 复制代码
explain select * from student where id = 3 - 1;

4、对索引做类型转换

对 stuno 字段创建索引:

sql 复制代码
create index idx_stuno on student(stuno);

where stuno= 1; stuno是 varchar,查询时使用 int ;索引失效

sql 复制代码
explain select * from student where stuno = 1;

where age = '15'; 对 int 类型使用 字符串查找,索引不失效

sql 复制代码
explain select * from student where age = '15';

5、or 连接的多条件查询中有非索引字段

id 和 stuno 都有索引 where id = 1 or stuno = '1'; 索引未失效

sql 复制代码
explain select * from student where id = 1 or stuno = '1';

将 stuno 的索引删除 ,走全表扫描

id 有索引, stuno 没有索引 where id = 1 or stuno = '1';

sql 复制代码
drop index idx_stuno on student;

explain select * from student where id = 1 or stuno = '1';

结语

本文分析了一些常见的索引失效的情况,各位小伙伴们在开发过程中还遇到哪些索引失效的情况呢,欢迎在评论区交流讨论。

祝各位创建的索引都能生效!

相关推荐
波力海苔夹心脆67520 分钟前
C# 正则表达式零基础入门:从“看得懂“到“会用“
经验分享·后端·mysql·正则表达式·c#
ClouGence2 小时前
数据如何随时可用?广西水牛先生的 MySQL 实时同步实践
数据库·mysql·数据分析
VX_bysjlw9854 小时前
基于协同过滤的美食推荐系统的设计与实现32221-计算机毕设原创(免费领源码+带部署教程)
java·spring boot·redis·mysql·tomcat·maven·mybatis
十碗饭吃不饱5 小时前
MySQL InnoDB RR 隔离下二级索引临键锁引发 INSERT 锁超时 全链路解析
java·数据库·mysql
Gh0st_Lx5 小时前
【2】MySQL 为什么使用 B+树
数据库·b树·mysql
我不会插花弄玉5 小时前
8. 复合查询【由浅入深-MySQL】
android·数据库·mysql
花间相见7 小时前
【计算基础|MySQL08】索引(上):为什么是 B+ 树
数据结构·mysql·算法·架构
我不会插花弄玉8 小时前
9. 表的内连和外连【由浅入深-MySQL】
android·数据库·mysql
小诗懂技术8 小时前
V4L2视频采集流程复习笔记
笔记·mysql·音视频