索引怎么又失效了?

索引失效的案例

导语

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

前置知识

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';

结语

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

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

相关推荐
苹果醋32 小时前
大模型实战--FastChat一行代码实现部署和各个组件详解
java·运维·spring boot·mysql·nginx
计算机学姐5 小时前
基于SpringBoot+Vue的高校运动会管理系统
java·vue.js·spring boot·后端·mysql·intellij-idea·mybatis
-XWB-5 小时前
【MySQL】数据目录迁移
数据库·mysql
掘根7 小时前
【MySQL】Ubuntu环境下MySQL的安装与卸载
数据库·mysql·centos
知识分享小能手7 小时前
mysql学习教程,从入门到精通,SQL 修改表(ALTER TABLE 语句)(29)
大数据·开发语言·数据库·sql·学习·mysql·数据分析
fat house cat_8 小时前
mysql-索引笔记
数据库·mysql
He guolin8 小时前
【MySQL】数据库基础知识
数据库·mysql
F_D_Z10 小时前
【SQL】未订购的客户
数据库·sql·mysql
shylyly_12 小时前
Linux的基本指令(3)
数据库·mysql·linux的基本指令
全职计算机毕业设计13 小时前
基于协同过滤的网络文学智能推荐平台的设计与实现(小说)springboot mysql Redis Thymeleaf
spring boot·后端·mysql