好的,请看这篇以程序员角度撰写的SEO优化软文:
MySQL索引失效场景
大家好,咱们程序员在面试数据库相关岗位,尤其是后端开发时,MySQL索引绝对是绕不开的重点知识。面试官特别爱问的就是:“什么情况下索引会失效啊?” 这个问题看似简单,但回答不全面或者踩了坑,很可能就与Offer失之交臂了。今天就来详细聊聊那些常见的MySQL索引失效场景,帮你面试时稳稳拿下这道题!
1. 对索引列使用函数或表达式
这是非常经典的一个坑!比如你有个用户表,birthday 是日期类型的列并且建了索引。你要查年龄大于30的人,如果写成 WHERE YEAR(CURDATE()) - YEAR(birthday) > 30,那完蛋了,索引大概率失效。数据库计算表达式的时候,是用不到索引的。正确姿势是直接比较日期:WHERE birthday < DATE_SUB(CURDATE(), INTERVAL 30 YEAR)。
关键词:索引失效, MySQL索引
2. 在索引列上进行运算操作
跟上一条类似,但更常见的是直接对列做加减乘除。假设有个订单表,amount(金额)有索引。你写 WHERE amount * 0.9 > 1000 想查打了9折后大于1000的订单?抱歉,数据库只能老老实实扫描全表计算每个 amount * 0.9,索引用不上。应该把计算移到右边:WHERE amount > 1000 / 0.9。
关键词:索引失效场景
3. 使用左模糊匹配(LIKE '%xxx')
模糊查询中,LIKE 'abc%' 这种右模糊或者 LIKE 'abc' 是可以用上索引的(如果是前缀索引或合适的数据类型)。但如果写成 LIKE '%abc' 或者 LIKE '%abc%'(左模糊或全模糊),数据库引擎就不知道从哪里开始匹配了,索引通常就失效了。想象一下,让你在字典里找一个以特定几个字母 结尾 的单词,你怎么快速找?得从头翻吧!同理,数据库面对左模糊也得全表扫。所以尽量避免左模糊,如果实在需要,考虑其他方案如全文索引。
关键词:MySQL索引失效, 索引失效
4. 违反最左前缀原则(Leftmost Prefix Rule)
这个原则是针对组合索引(也叫联合索引、复合索引)的命门!组合索引 (col1, col2, col3) 是按照 col1, col2, col3 的顺序建立索引树的。数据库想用这个索引,查询条件必须从索引的最左边列开始并且连续(中间不能跳过)。
- 能用索引的情况:
WHERE col1 = ?(用到了 col1)WHERE col1 = ? AND col2 = ?(用到了 col1, col2)WHERE col1 = ? AND col2 = ? AND col3 = ?(用到了 col1, col2, col3)WHERE col1 = ? AND col3 = ?(部分索引下推,能用上 col1 的索引部分,但 col3 可能不会用来过滤,效率不如用上 col2)
- 失效的情况:
WHERE col2 = ?(最左列 col1 没出现)WHERE col2 = ? AND col3 = ?(最左列 col1 没出现)WHERE col1 = ? AND col3 = ?(跳过了中间的 col2。虽然能用上 col1,但索引的效率会打折扣,有时优化器可能干脆选择全表扫)
设计组合索引和写 SQL 时,脑子里一定要有这个原则!
关键词:索引失效场景, MySQL索引失效, 最左前缀原则
5. OR 连接的非索引列
当 WHERE 子句中出现 OR 条件时,情况比较复杂。如果 OR 连接的列中存在至少一个列没有索引,那么整个查询可能就无法有效使用索引,导致全表扫描。例如:WHERE indexed_col = 'value' OR non_indexed_col = 'value'。优化策略通常是把 OR 拆成 UNION ALL(要注意去重问题)或者重新设计表结构给 non_indexed_col 加索引。
6. 数据类型隐式转换
数据库在比较时如果发现两边的数据类型不一致,会尝试进行隐式转换。比如索引列 phone 是 varchar 类型存储手机号,你写 WHERE phone = 13800138000(用了数字),数据库会把 phone 列的值都转成数字来比较,这就导致索引失效。正确的写法应该是 WHERE phone = '13800138000',保证类型匹配。这个小细节很容易忽略!
关键词:索引失效, MySQL索引失效场景
7. 查询优化器认为全表扫描更快
有时,即使有索引可用,查询优化器经过成本计算后,可能会认为扫描全表反而比走索引再回表更快。这种情况通常发生在:
- 表中数据量非常小。 索引本身也需要查找,数据量小的时候,直接读表可能更快。
- 索引的选择性太低。 比如在“性别”这种只有两个值的列上建索引,即使走了索引,回表查的数据量还是非常大(几乎一半),优化器可能觉得不如全表扫一次搞定。
- 查询需要获取表中大部分数据。 比如
SELECT * FROM table LIMIT 1000000, 10(获取大量数据偏移后的少量数据),索引扫描+大量回表的代价可能高于直接顺序扫描全表。
所以,索引不是万能的,优化器的选择是动态的。
关键词:索引失效, MySQL索引失效场景, 查询优化器
8. 使用NOT、NOT IN、NOT LIKE、!= 或 <> 操作符
这些否定操作符通常难以高效利用索引。数据库很难在索引中快速定位到“不等于某个值”的所有记录,往往需要扫描大部分索引或全表。例如 WHERE status != 'active',如果 status 索引,优化器可能还是会选择全扫。对于 NOT IN 和 NOT EXISTS,如果子查询结果集很大,效率也会很低。尽量用正向条件或考虑其他方案(如 LEFT JOIN ... IS NULL 代替 NOT IN)。
关键词:索引失效场景, MySQL索引
9. 索引列使用IS NULL 或 IS NOT NULL
在较早版本的 MySQL 或特定情况下,WHERE indexed_col IS NULL 可能用不到索引,需要全表扫描。但在较新版本(如 5.6+)且索引列允许为 NULL 的情况下,优化器通常能够利用索引来查找 IS NULL 的记录。不过,IS NOT NULL 依然可能导致索引失效,因为它通常意味着需要扫描索引中大量的非 NULL 值(除非 NULL 值占比很高)。具体情况最好用 EXPLAIN 查看执行计划确认。
10. 范围查询后的列无法使用索引
在组合索引中,如果某一列使用了范围查询(>, <, BETWEEN, LIKE 'prefix%' 等),那么该列之后的索引列将无法再用于索引过滤。例如索引 (col1, col2, col3),查询 WHERE col1 = 'a' AND col2 > 10 AND col3 = 'b'。数据库能用索引快速定位到 col1='a' 并且 col2>10 的记录,但对于 col3='b' 这个条件,由于 col2 用了范围查询,col3 在索引中是乱序的,无法高效利用索引进行等值匹配,只能回表后再过滤 col3。设计索引顺序时,尽量把等值查询的列放在范围查询列的前面。
关键词:MySQL索引失效, 组合索引, 索引失效
写在最后:
理解这些MySQL索引失效的场景,不仅仅是应付面试,对于日常开发写出高性能的SQL至关重要。面试前多想想这些点,回答时结合具体例子,面试官一定会对你刮目相看!
对了,如果大家需要购买面试鸭会员,可以通过 面试鸭返利网 (mianshiyafanli.com) 找到我,返利25元!能省一点是一点嘛。

最后送个福利!2025年Java面试宝典: 链接: https://pan.baidu.com/s/1RUVf75gmDVsg8MQp4yRChg?pwd=9b3g 提取码: 9b3g
希望这篇文章能帮助大家在面试路上少踩坑,早日拿下心仪的Offer!


