优秀的编程知识分享平台

网站首页 > 技术文章 正文

研究了 4.7 个小时终于了解到了索引使用了却没变快的原因

nanyue 2024-10-28 16:39:59 技术文章 3 ℃

引言:在软件开发中,我们经常会遇到一种情况:通过优化代码,尝试使用更有效的数据结构或算法,但最终性能并没有得到明显的提升,甚至有时还会变得更慢。这种情况下,我们可能会遇到“索引使用了却没变快”的情况,即我们认为使用索引应该能够提高查询效率,但实际上并没有得到预期的结果。

题目

研究了 4.7 个小时终于了解到了索引使用了却没变快的原因

推荐解析

前几天小鱼竟然碰见了加了索引,查询效率反而降低了 0.06% ,直到我排查才发现,原来可能是索引没生效,小鱼赶忙来总结一下没生效的原因。

可以用过 MySQL 的执行计划来查看索引是否有用 explain {SQL语句},主要观察几个点:

  • type(访问类型):这个属性显示了查询使用的访问方法,例如 ALLindexrange等。当查询使用索引时,这个属性通常会显示为 indexrange ,表示查询使用了索引访问。如果这个值是 ALL ,则表示查询执行了全表扫描,没有使用索引。
  • key(使用的索引):这个属性显示了查询使用的索引,如果查询使用了索引,则会显示索引的名称。如果这个值是 NULL,则表示查询没有使用索引。
  • rows(扫描的行数):这个属性显示了查询扫描的行数,即查询返回的行数。如果这个值很大,可能表示查询执行了全表扫描,而不是使用了索引。

对于用了索引一定就有用吗这个问题,我们排查要从两方面入手,具体如下:

索引真的生效了吗?

索引失效的场景有很多,也是面试官经常喜欢问的,可以根据具体场景进行排查,具体场景可以分为以下几点:

1)使用了联合索引却不符合最左前缀

举个例子:小鱼对 user 表建立了一个联合索引为 name_age_id 的联合索引,但是呢当他使用 SQL 查询的时候却是这样写的,select * where from age = 10 and id = 1; 这样的写法恰恰不满足最左前缀原则,索引就失效啦。

2)索引中使用了运算

举个例子:小鱼今天突发奇想,我试试新花样我直接在查询条件上运算怎么样!,那么如下 SQL 诞生了 select * from user where id + 3 = 8,真是聪明反被聪明误啊,这样恰恰导致了索引失效了,因为这样会导致全表扫描计算 id 的值再进行比较。

3)索引上使用了函数也会失效

小鱼真的懒死了!它连一点代码都不想写都想交给 MySQL 给他处理问题,它使用了函数让 MySQL 给他转换字段大小写,于是他写出了这样的 SQL 语句 select * from user where LOWER(name) like 'cong%';,这样也会导致索引失效,索引参与了函数处理,会导致去全表扫描喔。

4) like 的随意使用

相信小鱼写查询的时候都很喜欢将 % 写在首位,如:select * from user where name like '%cong%'; 这种情况就会导致索引失效喔,因为索引是从左到右来进行排序查找的,你的占位符直接放在了最左边开头,那么就直接导致要使用全表扫描啦~

5)or 的随意使用。

小鱼在 user 建了一个索引 name ,他以为稳了!写下了以下 SQL :select * from user where name= 'cong' or age = 18; 正是如此也导致了索引失效。不难看出当使用了 or 关键字时要两边同时都拥有索引才会生效喔~还有一种特殊的情况使用了 < 和 > 号也导致了索引失效因为是 or 使用了范围查询喔,例子如下:select * from user where age > 1 or age < 18;

6)随意的字段类型使用

粗心的小鱼将原本是 varchar 类型的 name 条件匹配了 int 类型字段,SQL 是这样的 select * from user where name = 1;,在代码中涉及 隐式转换 !将原本是 int 类型的 1 转成了 varchar 类型,这种情况也是不走索引的喔。

7)不同的参数也会导致索引失效

这个可能有点难以理解,具体 SQL 为 select * from user where age > 18;select * from user where age > 180; 根据数据量的不同,你有可能会发现前面那条走了索引而后面的却没走。这是因为当 MySQL 发现当使用了索引还不如直接全表扫描效率高,因此它会直接让索引失效。

8)表中两个不同字段进行比较

有天小鱼写了一条这样的 SQL :select * from user where id > age; ,小鱼他竟然将 idage 字段做了比较,好家伙!索引失效!

9)使用了 != 、<>

小鱼写的 SQL :select * from user where name != 'cong' ,可能会导致索引失效,这个场景下的 SQL 是否失效是根据查询到的数据集决定的,当数据大了的时候可能会导致索引失效。

10)使用了 is not null

注意使用了 is not null 会直接导致失效,而使用 is null 则不会。因为当使用 is not null 条件时,数据库系统需要扫描整个索引,找出所有不为 null 的值,这可能会导致索引失效。使用 is null条件不会导致索引失效,因为对于索引而言,查找 null 值的行与查找其他任何特定值的行都没有本质区别。在大多数情况下,null 值都会被索引包括在内。

11)使用了 order by

order by 后面跟的 不是主键 或者 不是覆盖索引 会导致不走索引。

为什么索引生效了反而查询变慢了呢?

1)索引也是需要占空间的。当数据少的时候,建立了多个索引反而会导致查询速度没效果反而更慢。

2)对大字段建立了索引。小鱼给 text 字段建立了索引导致查询需要扫描更多的数据块,反而变慢。

3)对重复值较多的字段建立索引。今天小鱼给性别字段建立了索引,他发现怎么查询还变满了!索引列的一些值重复度非常高,那么查询可能会导致大量的磁盘I/O操作,从而导致查询变慢。

其他补充

鱼聪明 AI 的回答:

鱼聪明 AI 地址:https://www.yucongming.com/

索引是数据库中用于加速数据检索的重要工具。虽然索引可以显著提高查询性能,但是有时候即使使用了索引,查询的速度并没有明显提升,这可能是由以下几个原因导致的:

  1. 索引选择不当: 选择正确的索引非常重要。如果选择了不适合查询模式的索引,或者索引覆盖的范围太大,查询可能仍然需要大量的扫描和过滤,导致性能不佳。
  2. 索引未被充分利用: 有时候,虽然查询中使用了索引,但是查询条件可能不充分利用索引,或者索引只被查询的一部分使用到。这可能是因为查询条件中包含了无法使用索引的函数、操作符或者类型转换,或者是因为查询条件中的索引列没有按照索引顺序使用。
  3. 查询优化不足: 查询本身可能存在性能问题,即使使用了索引也无法达到预期的性能。这可能是因为查询语句写得不够高效,或者需要进一步优化查询计划。
  4. 索引过度使用: 索引过多可能会导致性能下降,因为维护索引也需要成本。当数据库中存在大量索引时,更新数据时可能需要更新多个索引,从而增加了写操作的开销。
  5. 数据量过大: 即使使用了索引,如果数据量过大,查询仍然可能需要较长时间。在这种情况下,可能需要考虑其他的性能优化策略,如分区表、数据归档等。

推荐文章和书籍

文章:https://zhuanlan.zhihu.com/p/86293659

书籍:《 Java 核心技术卷 I 》

欢迎交流

当谈到索引生效问题时,我们可以探讨以下几个问题:

1)什么时候应该判断索引用了没生效?

2)如果索引生效了,反而更慢了呢?

3)索引究竟是怎么让我们的 SQL 提高速度的?

这些问题将帮助我们深入了解 索引的概念、应用和原理,从而更好用来解决实际问题。

最近发表
标签列表