MySQL索引失效场景面试题深度解析

2025年Java面试宝典:
链接: https://pan.baidu.com/s/1RUVf75gmDVsg8MQp4yRChg?pwd=9b3g
提取码: 9b3g
一、索引失效的核心原理
索引失效的本质是查询条件无法有效利用B+树的有序性。当SQL语句的编写方式导致无法通过索引快速定位数据时,就会触发全表扫描。理解这一点,就能更好地分析具体的失效场景。
二、高频索引失效场景详解
2.1 违反最左前缀原则
典型场景:
CREATE INDEX idx_name_age ON user(name, age);
SELECT * FROM user WHERE age = 25; -- 失效
失效原因:
复合索引的存储结构决定了必须按照索引字段顺序匹配。跳过第一个字段name直接查询age时,B+树的有序性被破坏,无法快速定位。
延伸考点:
- 部分匹配的情况:
WHERE name='张三' AND age>20(有效) - 乱序匹配的情况:
WHERE age=25 AND name='张三'(有效,优化器自动调整顺序)
2.2 对索引列进行运算或函数操作
典型场景:
SELECT * FROM orders WHERE YEAR(create_time) = 2023; -- 失效
失效原因:
对索引列使用函数后,数据库需要逐行计算函数结果,无法直接使用索引的有序性。应改为范围查询:
WHERE create_time BETWEEN '2023-01-01' AND '2023-12-31'
2.3 隐式类型转换
典型场景:
CREATE INDEX idx_phone ON user(phone); -- phone是varchar类型
SELECT * FROM user WHERE phone = 13800138000; -- 失效
失效原因:
将字符串类型的phone与数字比较时,MySQL会隐式转换所有phone值为数字,等价于对索引列使用函数。
2.4 OR条件使用不当
典型场景:
CREATE INDEX idx_age ON user(age);
SELECT * FROM user WHERE age=25 OR salary>10000; -- 失效
失效原因:
OR连接的两个条件中,只要有一个字段没有索引,就会触发全表扫描。建议改用UNION:
SELECT * FROM user WHERE age=25
UNION
SELECT * FROM user WHERE salary>10000;
2.5 模糊查询以通配符开头
典型场景:
CREATE INDEX idx_name ON user(name);
SELECT * FROM user WHERE name LIKE '%张%'; -- 可能失效
失效原因:
前导通配符%导致无法利用索引的有序性。但LIKE '张%'(无前导%)可以使用索引。
2.6 索引选择性差
典型场景:
CREATE INDEX idx_gender ON user(gender); -- gender只有'男'/'女'两种值
SELECT * FROM user WHERE gender='男'; -- 可能失效
失效原因:
当索引列的唯一值过少时(例如性别),数据库可能认为全表扫描比索引查询更快。
2.7 使用不等于操作符(!= / <>)
典型场景:
CREATE INDEX idx_age ON user(age);
SELECT * FROM user WHERE age != 25; -- 失效
失效原因:
不等于操作需要扫描所有不满足条件的记录,无法有效利用索引的有序性。
2.8 IS NULL / IS NOT NULL
典型场景:
CREATE INDEX idx_age ON user(age);
SELECT * FROM user WHERE age IS NULL; -- 可能失效
失效原因:
当表中大部分记录都满足IS NULL条件时,优化器可能选择全表扫描。
三、索引优化建议
- EXPLAIN命令:分析执行计划中的
type字段(至少达到range级别) - 覆盖索引:通过
SELECT具体字段减少回表操作 - 索引下推:MySQL 5.6+版本支持将WHERE条件过滤下推到存储引擎层



