索引怎么又失效了?

索引失效的案例

导语

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

前置知识

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

结语

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

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

相关推荐
夏炎正好眠28 分钟前
mysql练习
数据库·mysql
驜鸈2 小时前
MySQL 的EXPLAIN 计划 type 字段详细说明
android·数据库·mysql
嗨起飞了4 小时前
MySQL入门手册
数据库·mysql
程序员的世界你不懂5 小时前
Mysql配置文件My.cnf(my.ini)配置参数说明
数据库·mysql·百度·新浪微博
ChinaRainbowSea5 小时前
MySQL 索引的数据结构(详细说明)
java·数据结构·数据库·后端·mysql
追风赶月、5 小时前
【MySQL】事务(隔离性、MVCC)
数据库·mysql
Lemon_man_6 小时前
基于Django创建一个WEB后端框架(DjangoRestFramework+MySQL)流程
python·mysql·django
A仔不会笑8 小时前
MySQL面试篇——性能优化
java·数据库·mysql·面试·性能优化
考虑考虑9 小时前
MySQL中的DATE_FORMAT时间函数
数据库·后端·mysql
杭州刘同学9 小时前
autogen studio如何修改数据库为mysql
mysql·autogen