索引怎么又失效了?

索引失效的案例

导语

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

前置知识

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

结语

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

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

相关推荐
White_Mountain2 小时前
在Ubuntu中配置mysql,并允许外部访问数据库
数据库·mysql·ubuntu
老王笔记2 小时前
GTID下复制问题和解决
mysql
Lojarro4 小时前
【Spring】Spring框架之-AOP
java·mysql·spring
TianyaOAO4 小时前
mysql的事务控制和数据库的备份和恢复
数据库·mysql
Ewen Seong4 小时前
mysql系列5—Innodb的缓存
数据库·mysql·缓存
W21556 小时前
Liunx下MySQL:表的约束
数据库·mysql
nbsaas-boot7 小时前
探索 JSON 数据在关系型数据库中的应用:MySQL 与 SQL Server 的对比
数据库·mysql·json
奥顺8 小时前
PHPUnit使用指南:编写高效的单元测试
大数据·mysql·开源·php
苹果醋39 小时前
SpringBoot快速入门
java·运维·spring boot·mysql·nginx
ROCKY_8179 小时前
Mysql复习(一)
数据库·mysql