MySql数据库索引失效详解

1. 索引失效概述

提高数据库性能最常用的手段就是索引,当然索引也是比较有效的手段之一,但是在某些场景下索引会存在失效的情况,这就是本文探讨验证的主题。

2. 索引失效场景

常见索引失效的9种情况:
1.全值匹配:查询条件的列与索引列的字段,顺序完全相同。
2. 最佳左前缀:查询条件的列与索引列的字段相同,顺序不同,从不同顺序列开始后边都不走索引。
3. 索引计算:不要在索引上做任何计算
4. 索引范围:索引列上不能有范围查询,比如大于,小于,大于等于,小于等于。
5. 索引覆盖:尽量使用覆盖索引
6. 不等: 使用不等于(!= 或者 <>)的时候
7. null:字段的is not null 与is null
8. like:like的前后模糊匹配
9. or:减少使用or

总结:
全值匹配,左前缀。
索引计算范围要覆盖。
不等于(!= 或者 <>)扫全表,null走索引,not不走。
like模后不模前,见or就走union all

3. 索引失效验证

测试环境

3.1 全值匹配

-- 全值匹配
-- 查看sql执行计划
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30;
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 and deptid=4;
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 and deptid=4 AND emp.name = 'abcd';

-- 创建联合索引
CREATE INDEX idx_age_deptid_name ON emp(age,deptid,NAME);

创建索引前
在这里插入图片描述
创建索引后
在这里插入图片描述

3.2 最佳左前缀

-- 创建索引
CREATE INDEX idx_age_deptid_name ON emp(age,deptid,NAME);
-- 缺少联合索引的第一个字段
explain select sql_no_cache * from emp where deptId = 4 and name = 'abcd';
-- 联合索引的第一二个字段,缺少最后一个字段
explain select sql_no_cache * from emp where age = 30 and deptId = 4;
-- 联合索引的第一三各字段,缺少第二个字段
explain select sql_no_cache * from emp where age = 30 and name = 'abcd' ;

在这里插入图片描述查询字段与索引字段顺序的不同会导致, 索引无法充分使用, 甚至索引失效!
原因: 使用复合索引, 需要遵循最佳左前缀法则, 即如果索引了多列, 要遵守最左前缀法则。 指的是查询从索引的最左前列开始并且不跳过索引中的列。
结论: 过滤条件要使用索引必须按照索引建立时的顺序, 依次满足, 一旦跳过某个字段, 索引后面的字段都无法被使用

3.3 索引计算

不要在索引上做任何计算!
不在索引列上做任何操作(计算、 函数、 (自动 or 手动)类型转换), 会导致索引失效而转向全表扫描。

  1. 在查询列上使用函数
-- 索引不带计算
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE age=30;
-- 索引字段计算
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE LEFT(age,3)=30;

在这里插入图片描述
2. 在查询列上做了转换

-- 创建单值索引,字符串类型 name
create index idx_name on emp(name);
-- 字符串加单引号情况
explain select sql_no_cache * from emp where name='30000';
-- 字符串不加单引号, 则会在 name 列上做一次转换!
explain select sql_no_cache * from emp where name=30000;

在这里插入图片描述

3.4 索引范围:索引列上不能有范围查询

explain SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 and deptid=5 AND emp.name = 'abcd';
explain SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 and deptid<=5 AND emp.name = 'abcd';

在这里插入图片描述建议: 将可能做范围查询的字段的索引顺序放在最后

3.5 索引覆盖:尽量使用覆盖索引

explain SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 and deptId=4 and name='XamgXt';
explain SELECT SQL_NO_CACHE age,deptId,name FROM emp WHERE emp.age=30 and deptId=4 and name='XamgXt';

在这里插入图片描述

3.6.不等: 使用不等于(!= 或者 <>)的时候

mysql 在使用不等于(!= 或者<>)时, 有时会无法使用索引会导致全表扫描。
在这里插入图片描述

3.7. null:字段的is not null 与is null

当字段允许为 Null 的条件下:
is not null 用不到索引, is null 可以用到索引。
在这里插入图片描述在这里插入图片描述

3.8 like:like的前后模糊匹配

前缀不能出现模糊匹配!
在这里插入图片描述

3.9 or:减少使用or

在这里插入图片描述使用 union all 或者 union 来替代:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_37583655/article/details/121470002