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

本文涉及的产品
RDS AI 助手,专业版
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
简介: 本文总结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;
相关文章
|
存储 SQL 数据库
面试官:索引失效场景有哪些?
以下是内容的摘要: 本文列举了可能导致数据库索引失效的16种情况:全表扫描、索引列使用计算或函数、LIKE查询条件不匹配、未遵循联合索引最左前缀原则、索引列参与排序无筛选、隐式类型转换、OR条件连接索引、IN子句大量值、NOT操作、数据分布不均的JOIN、数据过于分散的查询、大结果集、临时表或派生表操作、索引维护不及时以及不等于比较和IS NOT NULL条件。这些情况都可能使查询优化器放弃使用索引,影响查询性能。
1237 1
|
存储 Java 编译器
JVM-不同jdk版本静态变量存储位置
JVM-不同jdk版本静态变量存储位置
|
5月前
|
资源调度 监控 测试技术
《SaaS多租户实战指南:从灰度发布到故障容错的全链路架构设计》
本文聚焦企业级团队协作SaaS应用的多租户架构迭代实践,针对租户规模差异大、资源冲突、定制化与标准化矛盾等核心痛点展开。初期简易多租户模式因资源共享导致故障后,作者重构架构:采用“独立数据库+共享数据库+租户标识”的混合隔离方案,解决数据隔离与成本平衡问题;搭建基于租户画像的弹性资源调度体系,通过预测式调度与实时调整提升资源利用率;以“核心标准化+定制插件化”架构,缩短定制需求响应时间;构建分层灰度发布与故障容错机制,将版本故障发生率大幅降低。最终总结出SaaS多租户架构需“以租户为中心”,在隔离、共享、定制间找到精细化平衡点的核心经验。
445 6
|
3月前
|
SQL 关系型数据库 MySQL
【数据库进阶】为什么你的SQL查询这么慢?索引失效的7个常见场景
本文总结MySQL索引失效的7大常见场景:模糊查询以%开头、索引列参与计算或函数、隐式类型转换、违背最左前缀法则、OR条件使用不当、不等号查询及全表扫描风险,并结合EXPLAIN工具教你如何诊断与优化,提升查询性能。
|
6月前
|
SQL JSON 关系型数据库
EXPLAIN详解:MySQL查询优化必备工具
本文深入解析了MySQL中的EXPLAIN命令,帮助开发者识别和优化慢查询。通过分析执行计划,读者可以了解查询的性能瓶颈,并采取相应措施提升数据库效率。
|
canal 缓存 NoSQL
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
根据对一致性的要求程度,提出多种解决方案:同步删除、同步删除+可靠消息、延时双删、异步监听+可靠消息、多重保障方案
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
|
存储 SQL 关系型数据库
MySQL高级篇——索引失效的11种情况
索引优化思路、要尽量满足全值匹配、最佳左前缀法则、主键插入顺序尽量自增、计算、函数导致索引失效、类型转换(手动或自动)导致索引失效、范围条件右边的列索引失效、不等于符号导致索引失效、is not null、not like无法使用索引、左模糊查询导致索引失效、“OR”前后存在非索引列,导致索引失效、不同字符集导致索引失败,建议utf8mb4
MySQL高级篇——索引失效的11种情况
|
4月前
|
机器学习/深度学习 关系型数据库 MySQL
什么是脏读、幻读、不可重复读?Mysql的隔离级别是什么?
脏读、不可重复读和幻读是数据库事务并发操作中的三种异常现象。脏读指读取到未提交的临时数据;不可重复读指同一事务内两次读取结果不一致,因数据被其他事务修改;幻读则是范围查询中出现新增记录,导致行数变化。SQL-92标准定义了四种隔离级别:未提交读(RU)、提交读(RC)、可重复读(RR)和串行化(Serializable),依次增强对这些异常的防控能力,平衡数据一致性与系统并发性能。
930 0
|
SQL 关系型数据库 MySQL
深入解析MySQL的EXPLAIN:指标详解与索引优化
MySQL 中的 `EXPLAIN` 语句用于分析和优化 SQL 查询,帮助你了解查询优化器的执行计划。本文详细介绍了 `EXPLAIN` 输出的各项指标,如 `id`、`select_type`、`table`、`type`、`key` 等,并提供了如何利用这些指标优化索引结构和 SQL 语句的具体方法。通过实战案例,展示了如何通过创建合适索引和调整查询语句来提升查询性能。
3108 10
|
SQL 安全 关系型数据库
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)
事务是MySQL中一组不可分割的操作集合,确保所有操作要么全部成功,要么全部失败。本文利用SQL演示并总结了事务操作、事务四大特性、并发事务问题、事务隔离级别。
5406 56
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)

热门文章

最新文章