mysql索引失效的五类典型场景:1.索引列被函数或运算包裹;2.like前导通配符;3.隐式类型转换;4.联合索引未遵循最左前缀原则;5.范围查询后列无法利用索引。

WHERE 条件中对索引列使用函数或运算
MySQL 无法使用索引加速 WHERE 子句中被函数包裹或参与运算的列,因为索引存储的是原始值,不是计算结果。
-
SELECT * FROM users WHERE YEAR(create_time) = 2023→create_time索引失效;应改用范围查询:create_time >= '2023-01-01' AND create_time -
WHERE age + 1 > 30→age索引不走;改写为age > 29 -
WHERE UPPER(name) = 'ALICE'→ 建议在写入时统一大小写,或添加函数索引(MySQL 8.0+):CREATE INDEX idx_name_upper ON users ((UPPER(name)))
LIKE 查询以通配符开头
LIKE 模式匹配中,前导 % 会强制全索引扫描或全表扫描,即使列上有索引。
-
WHERE name LIKE '%son'→ 索引失效;若业务允许,优先使用后缀匹配:name LIKE 'son%'(可走索引) - 需要前后模糊搜索时,考虑全文索引:
ALTER TABLE users ADD FULLTEXT(name),再用MATCH(name) AGAINST('son' IN NATURAL LANGUAGE MODE) - 短文本且查询频繁,可冗余生成拼音字段(如
name_pinyin)并建索引,避免函数实时转换
隐式类型转换导致索引失效
当 WHERE 中索引列与条件值类型不一致,MySQL 会自动转换——若转换发生在索引列一侧,索引就失效。
-
user_id是INT类型,但写成WHERE user_id = '123'→ 字符串常量触发隐式转整型,通常仍能走索引;但反过来:WHERE user_id = CONCAT('1', '23')或WHERE user_id = CAST('123' AS CHAR)就可能失效 - 更危险的是字符串字段存数字:如
phone VARCHAR(20)建了索引,却执行WHERE phone = 13812345678→ MySQL 把索引列转为数字比较,索引失效 -
解决方法:确保参数类型与字段定义严格一致;用
EXPLAIN验证type是否为ref或range,而非ALL或index
联合索引未遵循最左前缀原则
联合索引 (a, b, c) 只有在查询条件包含 a,或 a, b,或 a, b, c 时才能高效使用;跳过左侧列会导致索引部分或完全失效。
-
WHERE b = 2 AND c = 3→ 索引完全不走;必须带上a才行 -
WHERE a = 1 AND c = 3→ 仅a部分生效,c无法利用索引(b是断点) - 范围查询(
>,, <code>BETWEEN,LIKE 'xxx%')之后的列无法用索引:WHERE a = 1 AND b > 2 AND c = 3→c不走索引 - 高频查询字段尽量前置;必要时拆分索引,比如单独为
(b, c)建索引,但需权衡写入开销
EXPLAIN SELECT * FROM orders WHERE status = 'paid' AND amount > 100 AND created_at > '2024-01-01';
如果 orders 上只有联合索引 (status, created_at, amount),这个查询实际只用到 status,created_at 因为是范围条件,后面的 amount 列索引失效——这种细节容易被忽略,上线后慢查频发。










