MySQL索引失效的10种情况详解

顾言
顾言
发布时间:2026-10-16| 5人浏览过
原创

在MySQL数据库开发中,不当的SQL写法或索引设计会导致查询效率骤降。本文深入分析了导致MySQL索引失效的十种典型场景,涵盖最左匹配原则边界、范围查询对后续字段的影响、函数计算、类型隐式转换、逻辑运算符限制等方面。通过具体的EXPLAIN执行计划数据验证,揭示索引失效的根本原因,并提供相应的优化策略。

准备工作:构建测试环境

为了直观展示索引失效的效果,我们需要准备两张表进行演示:

1. 学生信息表 student_info(百万级数据):

CREATE TABLE `student_info` (
  `id` int NOT NULL AUTO_INCREMENT,
  `student_id` int NOT NULL,
  `name` varchar(20) DEFAULT NULL,
  `course_id` int NOT NULL,
  `class_id` int DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1000001 DEFAULT CHARSET=utf8;

2. 课程表 course(少量数据):

CREATE TABLE `course` (
  `id` int NOT NULL AUTO_INCREMENT,
  `course_id` int NOT NULL,
  `course_name` varchar(40) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8;

初始化数据后:select count(*) from student_info;(约100万行),select count(*) from course;(100行)。

一、违反最左匹配原则

在使用联合索引时,必须严格遵守“最左前缀”原则。以下四种操作会导致索引部分或完全失效:

第1步:查询跳过中间字段或丢失最左侧字段

前提:建立联合索引 idx_name_cou_cls on student_info(name,course_id,class_id)。

场景① 全部匹配(最优):

explain select * from student_info where name='11111' and course_id=10068 and class_id=10154;

该语句符合最左前缀原则,利用单个联合索引即可快速定位,性能最佳。

场景② 抹去最右边(有效但减少):

explain select * from student_info where name='11111' and course_id=10068;

联合索引依然生效,但仅利用了 (name, course_id)。通过观察执行计划的 key_len,可以发现它比全匹配时少了5字节(对应未用的 class_id)。

场景③ 跳过中间字段(部分失效):

explain select * from student_info where name='11111' and class_id=10154;

虽然使用了联合索引,但因为跳过了 course_id,B树只能快速查到所有 name='11111' 的记录,然后在内存中进行全表过滤来查找 class_id=10154。这比直接索引扫描要慢得多。key_len 只体现了最左边字段的长度。

场景④ 缺失最左侧(完全失效):

explain select * from student_info where class_id=10154 and course_id=10068;

未包含联合索引的最左列 name,导致联合索引彻底失效,退化为全表扫描。

第2步:范围条件导致右侧索引失效

原理:如果在联合索引中某个字段使用了范围查询(如 >, <),则其右边的所有列索引都会失效。

演示:使用 course_id > 1 作为范围条件,即使后面跟着精确条件的 class_id,class_id 也会被忽略。

explain select * from student_info where name='11111' and course_id>1 and class_id=1;

此时 key_len 只有68(仅为 name + course_id),证明 class_id 并未参与索引查找。

解决方案:将可能发生范围查询的字段尽量放在联合索引的最后面;或者将 >, < 转化为 >=, <= 的形式(此时右端索引不会失效)。例如:

explain select * from student_info where name='11111' and course_id>=20 and course_id<=40 and class_id=1;

这种写法下,所有索引字段均被用到。

二、字符集不统一与类型转换

第3步:字符串上的函数和运算

在查询时对索引列使用函数或表达式计算,会使得优化器无法直接使用B树中的值。

# 不使用索引(因为触发了LEFT函数)
explain select * from student_info where LEFT(name,2)='li';
# 不使用索引(因为进行了 name+'' 运算)
explain select * from student_info where name+''='lisi';

注意:使用通配符开头的模糊搜索同样会让B树失去意义:

# 以 % 开头,索引失效
explain select * from student_info where name like '%li';

第4步:隐式类型转换

当字段定义的格式与传入值的格式不一致时,MySQL会自动进行隐式转换,这本质上等同于对字段应用了函数,从而导致索引失效。

# name 是 varchar,这里传入了 int (123),导致隐式转为字符串比较失败或全表检索
explain select * from student_info where name=123;
# 正确使用字符串比较,能命中索引
explain select * from student_info where name='123';

三、特殊符号与逻辑判断的限制

第5步:不等于 (!= 或 <>)

不等号通常意味着需要进行全表查找,因此不会使用索引。

# 索引失效
explain select * from student_info where name <> 'zhangsan';
explain select * from student_info where name != 'zhangsan';

第6步:空值判断 (IS NULL vs IS NOT NULL)

IS NULL 可以利用索引快速定位空值,而 IS NOT NULL 无法通过常规索引加速。

# 可使用索引
explain select * from student_info where name is null;
# 索引失效
explain select * from student_info where name is not null;

建议:在设计表结构时,尽量给字段设置 NOT NULL 约束(例如INT默认0,字符串默认空串),以避免此类问题。

第7步:OR 条件混杂无索引列

如果 OR 前后的两个条件中,有一方没有索引,那么整个查询通常会放弃索引,转为全表扫描。

# OR两边都有索引 -> 可以使用索引
explain select * from student_info where name like 'li%' or course_id=200;
# class_id 没有索引 -> 索引失效,走全表扫描
explain select * from student_info where name like 'li%' or class_id=1;

四、创建高效索引的建议

为了避免上述索引失效的情况,在实际开发中可以遵循以下原则:

  • 单列索引选择:优先针对当前查询过滤性更高的字段创建索引。
  • 组合索引设计:在组合索引中,应当把过滤性最好的字段放在最前面,同时尽可能包含 WHERE 子句中更多的字段。
  • 处理范围查询:对于可能出现范围查询(>、<)的字段,务必将其放置在联合索引的后段,以免污染前面的匹配精度并导致后续字段失效。

以上就是 MySQL 导致索引失效的几种情况的详细内容,更多关于 MySQL 索引优化的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。