索引怎么又失效了?

索引失效的案例

导语

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

前置知识

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

结语

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

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

相关推荐
tatasix33 分钟前
MySQL UPDATE语句执行链路解析
数据库·mysql
天海华兮1 小时前
mysql 去重 补全 取出重复 变量 函数 和存储过程
数据库·mysql
武子康2 小时前
大数据-231 离线数仓 - DWS 层、ADS 层的创建 Hive 执行脚本
java·大数据·数据仓库·hive·hadoop·mysql
黑色叉腰丶大魔王3 小时前
《MySQL 数据库备份与恢复》
mysql
Ljw...3 小时前
索引(MySQL)
数据库·mysql·索引
OpsEye3 小时前
MySQL 8.0.40版本自动升级异常的预警提示
数据库·mysql·数据库升级
Ljw...3 小时前
表的增删改查(MySQL)
数据库·后端·mysql·表的增删查改
i道i11 小时前
MySQL win安装 和 pymysql使用示例
数据库·mysql
Oak Zhang12 小时前
sharding-jdbc自定义分片算法,表对应关系存储在mysql中,缓存到redis或者本地
redis·mysql·缓存
久醉不在酒13 小时前
MySQL数据库运维及集群搭建
运维·数据库·mysql