mysql索引失效的四大主因:①联合索引未按最左前缀使用;②在索引列上进行计算或函数操作;③字段与条件类型不匹配导致隐式转换;④like查询以通配符开头。

MySQL索引不是写了就一定生效的。很多看似合理的 SQL,执行时却悄悄退化成全表扫描——关键就在于某些操作“绕过了索引结构”。下面直接说清楚哪些场景会让索引失效,以及怎么写才靠谱。
联合索引没按最左列开始用
复合索引(比如 (name, age, city))就像电话簿:必须先翻“姓氏”,再找“名字”,最后看“年龄”。跳过前面的列,后面再准也没用。
-
失效示例:
WHERE age = 25或WHERE name = '张三' AND city = '北京'(中间跳过了age) - 正确做法:查询条件从左到右连续使用;高频组合可调整索引列顺序,比如把常用筛选字段放前面
在索引列上做计算或调函数
索引存的是原始值,一旦你对它加工(比如取年份、加减乘除),MySQL 就没法直接比对了——相当于查字典时把页码自己算一遍再去找,根本没法用目录。
-
失效示例:
WHERE YEAR(create_time) = 2025、WHERE price * 1.1 > 100、WHERE SUBSTR(phone, 1, 3) = '138' -
改写建议:把运算挪到右边,或改用范围表达式
✅create_time BETWEEN '2025-01-01' AND '2025-12-31'
✅price > 100 / 1.1
类型不匹配引发隐式转换
字段是 VARCHAR,你传数字;字段是 INT,你传字符串——MySQL 会偷偷帮你转类型,这等价于在字段上套了个函数,索引自然失效。
-
典型翻车:
WHERE phone = 13800001111(phone 是 varchar)、WHERE id = '123'(id 是 int) -
统一原则:字符串条件加单引号,数字条件不加引号;上线前用
EXPLAIN看key列是否为 NULL
LIKE 通配符放在开头
索引基于 B+ 树,支持“前缀匹配”;但 LIKE '%张' 或 LIKE '%张%' 没法利用树结构快速定位,只能扫全表。
-
能走索引的写法:
name LIKE '张%'(前缀确定) -
需要模糊搜索两端时:考虑全文索引(
FULLTEXT)、应用层预建反向索引,或用 Elasticsearch 等专用检索工具
其他常见失效点
这些虽不如上面四类高频,但同样容易踩坑:
-
用
OR连接条件:只要其中一端没索引,整条语句大概率放弃索引;可拆成UNION,或确保所有 OR 字段都有独立索引 -
用
!=或:优化器常认为全表扫描更快;必要时改写为> val OR -
IS NULL/IS NOT NULL:B+ 树索引默认不存 NULL 值;若业务频繁查空值,可加NOT NULL约束 + 默认值替代 -
范围查询后跟等值条件:在
(a,b,c)索引中,WHERE a > 10 AND b = 20只能用上a,b和c的索引失效
基本上就这些。核心就一条:让 MySQL 能**直接拿你的查询值去索引树里“查字典”**,别让它现场算、现场转、现场猜。写完 SQL 顺手加个 EXPLAIN,看一眼 key 和 type,心里就有底了。










