MySQL索引失效的几种常见场景详解

 更新时间:2025年09月02日 08:21:42   作者:努力学习java的哈吉米大王  
索引失效指的是在进行查询操作时,本应该使用索引来提升查询效率的场景下,数据库没有利用索引,而是采用了全表扫描的方式,这会大大增加查询时间和系统负担,这篇文章主要介绍了MySQL索引失效的几种常见场景的相关资料,需要的朋友可以参考下

我们在学习的过程中常能听到人们谈论到MySQL的索引失效了。那么为什么🧐索引会失效呢?

一、为什么索引会失效

我们需要知道索引的本质是以空间换时间的一种结构,“排好序的数据结构(例如InnoDB+树)”,能够帮助数据库快速定位数据。但是如果查询条件破坏了索引的有序性或者查询优化器判断“全表扫描比走索引更快”,就会放弃使用索引,导致索引失效。

接下来我们来以一些具体的场景来看!

二、索引失效的场景

2.1 对索引字段做“函数/运算操作”,破坏索引的有序性

索引存储的是字段原始值,一旦对字段做函数处理(如SUBSTR(),DATE())或者运算(如+,-),数据库无法直接使用索引定位,只能全表扫描。

-- 对索引字段name做函数处理,索引失效
SELECT * FROM user WHERE SUBSTR(name,1,3)='哈基米';

-- 对索引字段age做运算,索引失效
SELECT * FROM user WHERE age+3=24;

对于第二个SQL进行优化:把函数/运算移到等号右边

-- 以下两种都会走索引
SELECT * FROM user WHERE age=21;

SELECT * FROM user WHERE age=24-3;

2.2 隐式类型转换,导致索引字段被“隐式处理”

当查询条件中,字段类型与传入值类型不匹配时,MySQL会自动做类型转化(相当于隐式函数操作),导致索引失效

-- age是INT类型,传入字符串'21',会被转为INT(相当于CAST(age as CHAR))
SELECT * FROM user WHERE age='21'; -- 索引失效

对于这个SQL进行优化:保证传入的参数类型与字段类型相同

SELECT * FROM user WHERE age=21

2.3 LIKE查询以%开头,无法利用索引有序性

B+树索引是按照字段前缀排序的,LIKE '%XXX'表示“后缀匹配”,无法通过索引的有序性定位,只能全表扫描,而LIKE 'XXX%'(前缀匹配)可以走索引。

-- %在开头,索引失效
SELECT * FROM user WHERE name LIKE '%基米';

对于该SQL进行优化:不使用后缀匹配,如果业务必需后缀匹配,可以考虑“倒序存储+前缀索引”(如存name_reverse='米基哈',查询LIKE '米%')

2.4 组合索引不满足“最左前缀原则”

组合索引(a,b,c)的B+树是按照a->b->c的顺序排序的,查询条件必需包含最左列(a),否则不误利用索引。

-- 组合索引(a,b,c),缺少最左列a,索引失效
SELECT * FROM table1 WHERE b=2 AND c=2;

-- 虽然有a,但是中间列b缺失,只能用到a的索引,b和c无法利用
SELECT * FROM table1 WHERE a=2 AND c=2;

对上述的SQL进行优化:按最左前缀原则设计查询条件,或调整组合索引顺序(将高频字段放左边)

2.5 OR连接的条件中,存在未建索引的字段

OR的逻辑是“满足任意一个条件即可”,如果其中一个字段没索引,数据库无法通过索引快速定位所有满足条件的行(会查询到不满足非索引条件的行),只能放弃索引走全表扫描。

-- age有索引,name无索引,OR导致age索引失效
SELECT * FROM user WHERE age=21 OR name='哈基米';

对上述SQL进行优化:给OR连接的所有字段都建立索引,或改用UNION拆分查询:

SELECT * FROM user WHERE age=21
UNION
SELECT * FROM user WHERE name='哈基米'; -- 分别走各自的索引

注意📢:

假设字段age和name都有自己的索引

执行:SELECT * FROM user WHERE age=21 OR name='哈基米' ;

即使age和name分别有单独的索引,这个查询大概率不会走任何索引,会进行全表扫描

原因

OR的逻辑是“满足任意一个条件即可”,而数据库的索引是单个字段排序的:

  • age索引只能快速定位age=21的行;
  • name索引只能快速定位到name='哈基米'的行;
  • 数据库无法通过一个索引同事定位两个条件的结果,若分别使用两个索引再合并结果,开销可能比全表扫描更大(尤其是当两个条件的结果集都比较大时)

执行:SELECT * FROM user WHERE age=21 AND name='哈基米';

假设name和age都只有单独的索引,没有两者的组合索引时,数据库会选择其中一个过滤效果更好的索引(例如age=21能筛选出更少的行,则优先用age索引),定位后再在结果中过滤name='哈基米'的行。

2.6 查询优化器判断“全表扫描更快”

当数据量很少(例如几百行),或查询结果占表数据的大部分(如WHERE age=21返回90%的数据),查询优化器会认为“全表扫描比走索引更快”(索引也需要IO开销),此时会主动放弃索引。这种是“合理失效”,无效优化,数据库会自动选择最优方案。

2.7 其他场景

  • NOT IN/<>''!=:这些操作可能导致索引失效(视版本和数据分布而定),建议使用NOT EXISTS代替NOT IN
  • IS NULL/IS NOT NULL:早期MySQL版本对NULL处理不佳可能失效,新版本已优化,但扔建议字段尽量设置NOT NULL
  • USE INDEX等强制索引语句被优化器忽略:如果强制走索引但优化器判断效率更低,会忽略强制指令

三、如何避免索引失效

总结:

  1. 索引字段不做函数/运算,避免隐式类型转化
  2. 遵循组合索引的“最左前缀原则”
  3. LIKE查询尽量用前缀匹配(xxxx%)
  4. 用EXPLAIN分析SQL,关注type(是否为ALL)和Extra(是否有Using where)
  5. 结合业务场景设计索引

到此这篇关于MySQL索引失效的几种常见场景的文章就介绍到这了,更多相关MySQL索引失效内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 修改MySQL数据库中表和表中字段的编码方式的方法

    修改MySQL数据库中表和表中字段的编码方式的方法

    这篇文章主要介绍了如何修改MySQL数据库中表和表中字段的编码方式,需要的朋友可以参考下
    2014-05-05
  • MySql主键id不推荐使用UUID的原因分析

    MySql主键id不推荐使用UUID的原因分析

    MySQL的索引主要分为主键索引(PRIMARY KEY),唯一索引(UNIQUE) ,普通索引(INDEX)和全文索引(FULLTEXT) ,主键索引是一种特殊的唯一索引,不允许有空值,这篇文章主要介绍了MySql主键id不推荐使用UUID的原因分析,需要的朋友可以参考下
    2023-03-03
  • mysql心得分享:存储过程

    mysql心得分享:存储过程

    MySQL 5.0以后的版本开始支持存储过程,存储过程具有一致性、高效性、安全性和体系结构等特点,本文主要来分享下本人关于存储过程的一些心得体会。
    2014-07-07
  • Redis与MySQL如何保证双写一致性详解

    Redis与MySQL如何保证双写一致性详解

    双写一致性指的是当我们更新了数据库的数据之后redis中的数据 也要同步去更新,本文主要给大家详细介绍了Redis与MySQL双写一致性如何保证,需要的朋友可以参考下
    2023-09-09
  • MySQL 设计和命令行模式下建立详解

    MySQL 设计和命令行模式下建立详解

    这篇文章主要介绍了MySQL 设计和命令行模式下建立详解的相关资料,主要讲解了数据库的建立与数据表的设计,需要的朋友可以参考下
    2017-01-01
  • MySQL如何恢复单库或单表,以及可能遇到的坑

    MySQL如何恢复单库或单表,以及可能遇到的坑

    这篇文章主要介绍了MySQL如何恢复单库或单表,以及可能遇到的坑,帮助大家更好的备份数据库,保护数据安全,感兴趣的朋友可以了解下
    2020-09-09
  • 新手入门Mysql--概念

    新手入门Mysql--概念

    MySQL 是一种关系型数据库,在Java企业级开发中非常常用,因为 MySQL 是开源免费的,并且方便扩展MySQL是开放源代码的,因此任何人都可以在 GPL的许可下下载并根据个性化的需要对其进行修改
    2021-06-06
  • 101个MySQL优化技巧和提示

    101个MySQL优化技巧和提示

    人们一直在推动MySQL发展到它的极限。这里是101条调节和优化MySQL安装的技巧。一些技巧是针对特定的安装环境的,但这些思路是通用的。我已经把他们分成几类,来帮助你掌握更多MySQL的调节和优化技巧。
    2014-02-02
  • 一文带你学会MySQL的select语句

    一文带你学会MySQL的select语句

    在MySQL中可以使用SELECT语句来查询数据,查询数据是指从数据库中根据需求,使用不同的查询方式来获取不同的数据,是使用频率最高、最重要的操作,下面这篇文章主要给大家介绍了关于MySQL中select语句的相关资料,需要的朋友可以参考下
    2022-11-11
  • mysql缺少my.ini文件的最佳解决方法

    mysql缺少my.ini文件的最佳解决方法

    my.ini是MySQL数据库中使用的配置文件,修改这个文件可以达到更新配置的目的,下面这篇文章主要给大家介绍了关于mysql缺少my.ini文件的最佳解决方法,需要的朋友可以参考下
    2024-01-01

最新评论