mysql 索引失效?怎么解决? (重点知识,建议收藏,读10遍+)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
云数据库 RDS PostgreSQL,高可用系列 2核4GB
简介: 本文总结MySQL索引失效的八大常见场景,如函数操作、类型不匹配、OR连接、违背最左前缀等,并结合实际案例解析。通过EXPLAIN分析执行计划,帮助开发者识别问题,提供优化策略,提升查询性能。

前言

最近,公司的后台页面有一个接口查询太慢,让调查修复。我看了一下,是把日期作为查询条件时,写sql时将日期进行了格式化,导致了索引失效。

因此,这次想跟大家聊聊mysql索引失效的一些场景,并结合我工作中实际遇到的情况进行说明,希望能对大家有一点帮助


一、什么是索引失效?

定义: 索引失效 就是指mysql 在实际执行中没有扫描索引而是直接扫描全表。一般会导致查询变慢。

二、如何判断索引是否失效?

  • 使用EXPLAIN
    EXPLAIN SELECT ...;
    

• type: 从好到差依次是:system > const > eq_ref > ref > range > index > ALL(性能排序)

• key: 实际使用的索引,如果为NULL则表示未使用索引

  • 查看索引使用情况:
    SHOW STATUS LIKE 'Handler_read_rnd_%';
    SHOW STATUS LIKE 'Handler_read_key';
    

三、MySQL索引失效的常见场景

场景一:索引列上使用函数或表达式

  • 原因:因为索引上保存的是原始的值,当对列进行运算后,mysql 就无法直接通过索引来匹配数据;从而导致索引失效。

这也是我开头提到的场景

解决方法就是避免在索引列上添加函数或者表达式,有需求的话可以在业务代码层面做处理

示例:

-- ❌ 索引失效
WHERE DATE(order_date) = '2024-04-21'

-- ✅ 改写方式
WHERE order_date BETWEEN '2024-04-21' AND '2024-04-22'

场景二:数据类型不一致或不匹配

  • 原因: 当数据类型不匹配时,数据库会执行隐式类型转换。这相当于在列上使用了一个转换函数,就又回到了场景一的情况,不过这次的函数时mysql替你加的。

示例:

-- 索引字段为INT,但查询条件用字符串
-- ❌ 索引失效(字符串类型)
SELECT * FROM users WHERE id='123';

-- ✅ 索引有效(int 类型)
SELECT * FROM users WHERE id=123;

场景三: 使用不等于(<>!=)操作符

  • 原因:不等于的话mysql要找到除了后面特定值的所有数据,此时mysql大概率会认为我直接全部扫描比先找到这条记录,再找它前面和后面的要更快些,从而选择执行全表扫描
  • 注意:这里说的是大概率,并不是mysql 100% 不走索引,具体如何执行要看mysql内部的优化器如何决定

示例:

-- ❌ 索引大概率失效
SELECT * FROM products WHERE price <> 100

场景四: 使用not in或`NOT EXISTS

  • 原因:基本和场景三是一样的,都看你排除数据的多少

示例:

-- ❌ 索引大概率失效
SELECT * FROM products WHERE price not in (100,200)

场景五:使用OR连接条件

原因:如果OR条件的列都在索引的前缀中,优化器可能会尝试使用索引,否则难以利用索引,可能会退化为全表扫描

示例:

-- ❌ 索引大概率失效
SELECT * FROM users WHERE username = 'morty' OR age = 18;
-- 情况1: 只有 idx_username 存在,email 无索引 -> 索引 idx_username 对 OR 条件整体失效(需全表扫)。
-- 情况2: 如果同时存在 idx_username 和 idx_age -> 优化器有可能使用 Index Merge 策略,此时两个索引都可能会生效。

优化策略:
使用`UNION ALL:

-- ✅ 索引有效
SELECT * FROM users WHERE username='morty';
union all
SELECT * FROM users WHERE age=18;

场景六:未遵循 最左匹配原则/ 前缀匹配

我感觉这两个的原理讲起来类似,因此放到一块说了

原理: 原理其实很简单,就是mysql的索引都是有序的,你查询的条件要确定是有序的才可以通过索引优化,违背最左匹配原则就代表了查询的条件已经是无序的了,从而导致索引失效

示例:

-- 索引 为联合索引idx_country_city 先country 再city
-- ❌ 索引失效,因为跳过了最左列 `country`,coutry的数据是无序的
SELECT * FROM users WHERE city = 'New York'; 
-- ✅ 索引有效
SELECT * FROM users WHERE country = 'beijing'; 

-- ❌ 索引失效 以doe结尾的数据不是有序的
SELECT * FROM users WHERE username LIKE '%doe'; 
-- ✅ 索引有效
SELECT * FROM users WHERE username LIKE 'doe%';

场景七:排序不当,导致索引失效

-- 1. ORDER BY 与 WHERE 子句不匹配:

-- 两个独立的索引 name 和height。   ❌ 索引失效 
select height from users where name like 'a%' order by height;

-- 建立联合索引(name,height)。    ✅ 索引有效
select height from users where name like 'a%' order by height;

-- 2.范围条件导致索引失效  
-- ❌ 索引失效
SELECT * FROM products WHERE price > 100 ORDER BY price LIMIT 10;

-- 3. 使用 `ORDER BY` 的列与索引排序方式不一致:

-- 索引 (country, city ASC) 可能用于 WHERE  ❌ 索引失效
SELECT * FROM users WHERE country = 'US' ORDER BY city DESC; 
-- 创建索引 (country, city DESC) 可以优化这个查询。   ✅ 索引有效
SELECT * FROM users ORDER BY country ASC, city DESC;

场景八:JOIN 字段字符集/排序规则不一致

场景:跨表 JOIN 时字段字符集不同

这个场景是我实际遇到但很少看到有资料介绍到的,当时排查了好多方向,就是没想到是字符集的问题,希望能帮大家避坑

table1.utf8_col (utf8mb4) JOIN table2.latin1_col (latin1)

  
原理:隐式转换导致索引失效

解决:统一字符集或显式转换

ON CONVERT(utf8_col USING latin1) = latin1_col

四、应对策略:避免索引失效

  1. 避免在列上使用函数或表达式
  2. 保持数据类型一致
  3. 按筛选条件字段顺序建立复合索引
  4. 优化OR条件,将其拆分为多个查询
  5. 监控查询计划,结合EXPLAIN分析调优
  6. 合理使用覆盖索引,减少回表
  7. 避免在索引列上进行模糊匹配(LIKE '%abc%')

五、总结

索引是提升查询性能的关键,但并非万能。理解索引失效场景,合理设计索引和优化SQL,才是真正的“杀手锏”。做好索引优化,你的MySQL性能会有质的飞跃!

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
Java API 开发工具
如何用阿里云 oss 下载文件
阿里云对象存储服务(OSS)提供了多种方式下载文件,以下讲解下各种方式的下载方法
10288 2
|
1月前
|
机器学习/深度学习 缓存 自然语言处理
【万字长文】大模型训练推理和性能优化算法总结和实践
我们是阿里云公共云 AI 汽车行业大模型技术团队,致力于通过专业的全栈 AI 技术推动 AI 的落地应用。
1038 38
【万字长文】大模型训练推理和性能优化算法总结和实践
|
4月前
|
存储 SQL 关系型数据库
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
|
27天前
|
安全 前端开发 Java
《深入理解Spring》:现代Java开发的核心框架
Spring自2003年诞生以来,已成为Java企业级开发的基石,凭借IoC、AOP、声明式编程等核心特性,极大简化了开发复杂度。本系列将深入解析Spring框架核心原理及Spring Boot、Cloud、Security等生态组件,助力开发者构建高效、可扩展的应用体系。(238字)
|
3月前
|
设计模式 XML 安全
Java枚举(Enum)与设计模式应用
Java枚举不仅是类型安全的常量,还具备面向对象能力,可添加属性与方法,实现接口。通过枚举能优雅实现单例、策略、状态等设计模式,具备线程安全、序列化安全等特性,是编写高效、安全代码的利器。
|
消息中间件 Java Kafka
Kafka启动遇到ERROR Exiting Kafka due to fatal exception (kafka.Kafka$)
Kafka启动遇到ERROR Exiting Kafka due to fatal exception (kafka.Kafka$)
1524 0
|
4月前
|
消息中间件 供应链 前端开发
如何开发供应商管理系统中的订单协同板块(附架构图+流程图+代码参考)
在现代企业供应链管理中,订单协同是连接采购、销售、供应商与库存的重要环节。本文详解供应商管理系统中订单协同板块的设计与实现,涵盖功能模块、业务流程、技术架构及代码示例,帮助企业提升供应链效率,降低库存风险,优化订单管理流程。
|
canal 缓存 NoSQL
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
根据对一致性的要求程度,提出多种解决方案:同步删除、同步删除+可靠消息、延时双删、异步监听+可靠消息、多重保障方案
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
|
11月前
|
SQL 安全 关系型数据库
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)
事务是MySQL中一组不可分割的操作集合,确保所有操作要么全部成功,要么全部失败。本文利用SQL演示并总结了事务操作、事务四大特性、并发事务问题、事务隔离级别。
4682 56
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)