Mysql进阶优化篇02——索引失效的10种情况及原理 2

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: Mysql进阶优化篇02——索引失效的10种情况及原理

3.4 计算、函数、类型转换(自动或手动)导致索引失效

思考:这两条 sql 哪种写法更好?

EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE student.name LIKE 'abc%';
EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE LEFT(student.name,3) = 'abc'; 

从执行结果上说,上面sql执行结果没有区别。但是从运行效率上说,第1条sql比之后的要好,因为第一条可以使用上索引!而因为第二条使用了函数,即使建立索引也会导致索引失效。

为何使用函数时优化器会使索引失效呢?您想想,我们只是对student.name字段建立了索引,但并没有对LEFT(student.name,3)建立索引,使用函数后的关键字跟我们建立的B+树可对应不来,怎么能使用B+树优化查询呢?

3.5 类型转换导致索引失效

# 未使用到索引
EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE name=123;
# 使用到索引
EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE name='123';

name = 123 发生类型转换,索引失效,原因与使用函数也一样,其实类型转换就是使用了隐式的类型转换函数。

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

我们先调用下前面准备的存储过程删除除主键索引外的其它索引。

CALL proc_drop_index('atguigu_db2','student');
SHOW INDEX FROM student;

创建联合索引。

CREATE INDEX idx_age_classId_name ON student(age,classId,NAME);

执行查询。

EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE student.age=30 AND student.classId>20 AND student.name = 'abc' ;

执行结果如下。

c7c0d4c4ec1a4cc2baea89af8657d361.png

注意到key_len是10,说明值使用到了idx_age_classId_name索引中的ageclassId部分,而name则没有用上。这是因为classId>20是范围查询,导致其右边的列索引失效。

如果想要完全使用到索引,需要按如下方式创建索引:先写等值查询的列,再写范围查询的列。

create index idx_age_name_classid on student(age,name,classid);

🎨Q:为什么条件查询会导致范围条件后面的列索引失效?

比如说有三个字段 a b c,建立复合索引a_b_c

此时叶子节点的数据排序后可能为

(a=1 b=1 c=1) (a=1 b=2 c=1) (a=1 b=2 c=3)

(a=2 b=2 c=3) (a=2 b=2 c=5) (a=2 b=5 c=1) (a=2 b=5 c=2)

(a=3 b=0 c=1) (a=3 b=3 c=5) (a=3 b=8 c=6)

假设查找 select a,b,c from table where a = 2 and b = 5 and c = 2

此时先根据a = 2找到第二行的四条数据

(a=2 b=2 c=3) (a=2 b=2 c=5) (a=2 b=5 c=1) (a=2 b=5 c=2)

然后根据b=5查到两条

(a=2 b=5 c=1) (a=2 b=5 c=2)

最后根据c=2查到目标数据

(a=2 b=5 c=2)

接下来 假设使用了范围条件

select a,b,c from table where a = 2 and b >1 and c = 2

此时先根据a = 2找到第二行的四条数据

(a=2 b=2 c=3) (a=2 b=2 c=5) (a=2 b=5 c=1) (a=2 b=5 c=2)

然后根据b>1查到四条数据

(a=2 b=2 c=3) (a=2 b=2 c=5) (a=2 b=5 c=1) (a=2 b=5 c=2)

此时要查找c=2了 但是我们发现 这四条数据的c分别是

3,5,1,2 是无序的 所以索引失效了

总结:

因为前一个条件相同的情况下,后续列才会是有序的。

🎃Tips:

应用开发中范围查询,例如:金额查询,日期查询往往都是范围查询。应将查询条件放置where语句最后。(创建的联合索引中,务必把范围设计到的字段写在最后)

3.7 不等于(!= 或者 <>)索引失效

为name字段创建索引

CREATE INDEX idx_name ON student(NAME);

查看索引是否失效

EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE student.name <> 'abc' ;
EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE student.name != 'abc' ;

执行结果如下。

535635492d8a4e98a39964915141d002.png

没有失效!!!这个原因还不是特别明确,可能mysql高版本中优化器又做了升级(毕竟不等于不过是等于的取反,确实可以实现优化)?笔者的mysql版本为8.2.06,如果有知道的大佬可以在评论区留言讨论。不过在实际生产或者面试中,这仍然可以作为一种需要关注的特殊情形。

3.8 is null可以使用索引,is not null无法使用索引

原因和原理一模一样。

EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE age IS NULL;

f0fee2c5a489470ab0fc245cd6a1d0b1.png

EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE age IS NOT NULL;

同样的,在低版本中索引会失效,高版本中,索引也不会失效哦。

d1ff747d4d1a483f9714a3ee18ff050e.png


🎑结论:最好在设计数据库的时候就将 字段设置为 NOT NULL 约束。比如可以将 INT 类型的字段,默认设置为 0。将字符串的默认值设置为空字符串(“”)。

扩展:同理,在查询中使用 not like 也无法使用索引,导致全表扫描

3.9 like 以通配符 % 开头索引失效

在使用 LIKE 关键字进行查询的查询语句中,如果匹配字符串的第一个字符为“%”,索引就不会其作用。只有“%”不在第一个位置,索引才会起作用。

使用到索引

EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE NAME LIKE 'ab%'; 

e4921919d84a44498993423e42b0e8be.png

未使用到索引.

EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE NAME LIKE '%ab%';


131dfb01ed65468b97d34745c3f19b6b.png

想想那颗b+树,前面模糊了那么排序还有什么用?

🎠拓展:Alibaba《Java 开发手册》

【强制】页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎来解决。


3.10 OR前后存在非索引的列

在WHERE 子句中,如果在 OR 前的条件列进行了索引,而在 OR 后的条件列没有进行索引,那么索引会失效。也就是说,OR 前后的两个条件中的列都是索引时,查询中才使用索引。

因为 OR 的含义就是两个只要满足一个即可,因此 只有一个条件列进行了索引是没有意义的,只要有条件列没有进行索引,就会进行全表扫描,因此索引的条件列也会失效。

查询语句使用 OR 关键字的情况:

#清除现有的索引
CALL proc_drop_index('mymysql', 'student')
# 创建索引
CREATE INDEX idx_age ON student(age);
# 未使用到索引
EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE age = 10 OR classid = 100;

b6508b5156e94db58c6ac7773b1e16d3.png

这是因为or连接的查询条件都需要查询,如果一个使用索引,一个不用索引全表扫描,索引根本起不到优化性能的作用。还不如只进行一次全表扫描呢。

解决方式是给未使用索引的列创建索引。

# 再创建一个索引
CREATE INDEX idx_cid ON student(classid);
#使用到索引
EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE age = 10 OR classid = 100;

又翻车了·。。。看来这个情况还是得特别小心啊。

79a8aaefcb854e37863c56a921c9e32c.png

再来。

EXPLAIN SELECT SQL_NO_CACHE  age,classid FROM student WHERE age = 10 OR classid = 100;

5e8a0b8475284f63a53322fc71879e62.png

总结:没事别用select *。

3.11 数据库和表的字符集不匹配

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

4.索引一般性建议

假设,index(a,b,c),下面罗列了一些值得被注意的索引应用场景。


f307297a021f4178a3a32230d71c2f6d.png

🎉建议

对于单列索引,尽量选择针对当前 query 过滤性更好的索引

在选择组合索引的时候,当前 query 中过滤性最好的字段在索引字段顺序中,位置越靠前越好

在选择组合索引的时候,尽量选择能够包含当前 query 中的 where 子句中更多字段的索引

在选择组合索引的时候,如果某个字段可能出现范围查询时,尽量把这个字段放在索引次序的最后面。

总之,书写 SQL 语句时,尽量避免造成索引失效的情况。


相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
7天前
|
关系型数据库 MySQL 索引
mysql 分析5语句的优化--索引添加删除
mysql 分析5语句的优化--索引添加删除
8 0
|
13天前
|
存储 关系型数据库 MySQL
轻松入门MySQL:数据库设计之范式规范,优化企业管理系统效率(21)
轻松入门MySQL:数据库设计之范式规范,优化企业管理系统效率(21)
|
13天前
|
存储 SQL 关系型数据库
轻松入门MySQL:加速进销存!利用MySQL存储过程轻松优化每日销售统计(15)
轻松入门MySQL:加速进销存!利用MySQL存储过程轻松优化每日销售统计(15)
|
13天前
|
存储 关系型数据库 MySQL
轻松入门MySQL:优化进销存管理,掌握MySQL索引,提升系统效率(11)
轻松入门MySQL:优化进销存管理,掌握MySQL索引,提升系统效率(11)
|
15天前
|
存储 SQL 关系型数据库
mysql优化一
mysql优化一
15 0
|
7天前
|
SQL 缓存 关系型数据库
mysql性能优化-慢查询分析、优化索引和配置
mysql性能优化-慢查询分析、优化索引和配置
66 0
|
13天前
|
存储 关系型数据库 MySQL
MySQL数据库性能大揭秘:表设计优化的高效策略(优化数据类型、增加冗余字段、拆分表以及使用非空约束)
MySQL数据库性能大揭秘:表设计优化的高效策略(优化数据类型、增加冗余字段、拆分表以及使用非空约束)
|
13天前
|
缓存 关系型数据库 MySQL
MySQL查询优化:提速查询效率的13大秘籍(合理使用索引合并、优化配置参数、使用分区优化性能、避免不必要的排序和group by操作)(下)
MySQL查询优化:提速查询效率的13大秘籍(合理使用索引合并、优化配置参数、使用分区优化性能、避免不必要的排序和group by操作)(下)
|
13天前
|
缓存 关系型数据库 MySQL
MySQL 查询优化:提速查询效率的13大秘籍(索引设计、查询优化、缓存策略、子查询优化以及定期表分析和优化)(中)
MySQL 查询优化:提速查询效率的13大秘籍(索引设计、查询优化、缓存策略、子查询优化以及定期表分析和优化)(中)
|
13天前
|
存储 关系型数据库 MySQL
MySQL 查询优化:提速查询效率的13大秘籍(避免使用SELECT *、分页查询的优化、合理使用连接、子查询的优化)(上)
MySQL 查询优化:提速查询效率的13大秘籍(避免使用SELECT *、分页查询的优化、合理使用连接、子查询的优化)(上)

推荐镜像

更多