前言

索引可以用来提高查询性能,这个大家都知道。但是很多时候,明明有索引了,但查询还是很慢,用执行计划一看发现没有走索引,这时候你可能懵逼了。 其实关键索引失效的几种情况,你对使用索引的细节不够了解,本文将带你深入分析索引失效的底层原理,然后通过几个索引失效的场景进行加强索引失效的几种情况,相信再也不用担心为什么你的SQL慢了。

索引失效的_失效索引种情况怎么填_索引失效的几种情况

索引失效原理

可能大家多多少少都听过,查询没遵循最左前缀法则、范围查询的右边会导致索引失效等等,但是有想过为什么吗?

基于索引查询流程

谈到索引失效的原理前,我们需要先弄明白MySQL是怎么利用索引去查询数据的。

索引的底层数据结构是B+树,如果对于这块内容不了解的,强烈建议大家先阅读:一步步带你设计MySQL索引数据结构

数据准备:

一张用户表user, 数据如下:

id

name

age

sex

18

16

最终得到的索引如下图所示:

失效索引种情况怎么填_索引失效的_索引失效的几种情况

现在如果要执行 * from user where name='a' and age = 8语句,它的整个查询执行流程是怎么样的?

MySQL会把根目录节点所在页加载到内存中,因为是排好序了,根据'(a,8)'通过二分法快速找到它的下一层目录节点所在的页。MySQL再次把下一层目录节点所在的页加载到内存中,通过二分法找到对应的页。最终找到叶子节点,得到的它的主键id。然后根据主键id回到聚簇索引的B+树种,按照上面类似的流程再次定位到具体的行数据。这个过程也叫做回表。失效原因分析

前面分析了一个基于索引进行查询的执行流程,简单来说,它是拿着你索引字段的查询值去B+树中匹配,快速的定位它所在的数据行。

那如果我们的查询值,不是按照B+树中存储的顺序去查,那MySQL显然就无法通过索引去快速查找了,直接上例子。

例子: 查找 * from user where age = 8

因为联合索引B+树中的顺序是根据先对name排序,其次在name确定的情况下,在name下对age排序,所以age=8可能出现在任何一个目录节点中。现在name都没有,MySQL就无法快速通过二分法查找了,难不成让它对B+树中的每个节点,那我还不如直接全表查询呢。

同理,like 'aaaa%' 支持索引, like '%aaaa'不支持,因为like 'aaaa%' 前面部分是确定的,可以利用B+树去搜索。

这也就是我们通常说的 “最左前缀法则” 。

其他注意点

是不是用上索引,最终都是优化器说了箅。优化器是基于什么的优化器?基于cost开销(),它不是基于规则(),也不是基于语义。怎么样开销小就怎么来。另外,SQL语句是否使用索引,跟数据库版本、数据量、数据选择度都有关系。

索引失效情况

准备数据:

CREATE TABLE `student` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `stuno` INT NOT NULL ,
    `name` VARCHAR(20) DEFAULT NULL,
    `age` INT(3) DEFAULT NULL,
    `classId` INT(11) DEFAULT NULL,
    PRIMARY KEY (`id`)
    #CONSTRAINT `fk_class_id` FOREIGN KEY (`classId`) REFERENCES `t_class` (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
复制代码

1. 不遵守最左前缀法则索引失效

存在联合索引:

CREATE INDEX idx_age_classid_name ON student(age,classId,name);
复制代码

例子:没有走索引

失效索引种情况怎么填_索引失效的几种情况_索引失效的

2. 范围条件右边的列索引失效

存在联合索引:

CREATE INDEX idx_age_classid_name ON student(age,classId,name);
复制代码

例子:

正常情况下:

失效索引种情况怎么填_索引失效的_索引失效的几种情况

范围查询> :

失效索引种情况怎么填_索引失效的_索引失效的几种情况

索引失效的_失效索引种情况怎么填_索引失效的几种情况

3. 函数、计算导致索引失效

存在索引:

CREATE INDEX idx_name ON student(NAME);
复制代码

例子:

失效索引种情况怎么填_索引失效的几种情况_索引失效的

4. 类型转换导致索引失效

存在索引:

CREATE INDEX idx_name ON student(NAME);
复制代码

例子:

失效索引种情况怎么填_索引失效的_索引失效的几种情况

5. 不等于可能导致索引失效

存在索引:

CREATE INDEX idx_name ON student(NAME);
复制代码

例子:

索引失效的_失效索引种情况怎么填_索引失效的几种情况

6. is not null可能导致索引失效

存在索引:

CREATE INDEX idx_name ON student(NAME);
复制代码

例子:

失效索引种情况怎么填_索引失效的几种情况_索引失效的

7. like以通配符%开头导致索引失效

存在索引:

CREATE INDEX idx_name ON student(NAME);
复制代码

例子:

失效索引种情况怎么填_索引失效的几种情况_索引失效的

8. OR 前后存在非索引的列,索引失效

存在索引:

CREATE INDEX idx_name ON student(NAME);
复制代码

例子:

索引失效的几种情况_失效索引种情况怎么填_索引失效的

9. 数据分布导致索引失效

表中的字段很集中,比如性别,这时候MySQL评估使用索引比全表更慢,则不使用索引。有一种说法是当查询的数据量超过全表的30%,就不再走索引,而直接全表扫描。

10. 隐式字符编码转换导致索引失效

统一使用兼容性更好,统一字符集可以避免由于字符集转换产生的乱码。不同的字符集进行比较前需要进行转换会造成索引失效。

总结

本文讲解了索引失效的深层次原因,以及常见的一些索引失效的情况,大家可以反查下项目中的SQL, 是否有踩雷的。如果本文对你有帮助的话,请留下一个赞吧。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注