MySQL索引失效是优化器因成本高主动弃用索引,表现为type: ALL、key: NULL;对索引列使用函数或表达式(如DATE()、UPPER()、age+1)导致无法匹配索引树原始值。

MySQL索引失效不是“索引坏了”,而是优化器在生成执行计划时,判断走索引的成本高于全表扫描,于是主动放弃使用索引——最终表现为 type: ALL、key: NULL。
WHERE 条件里对索引列用了函数或表达式
索引树里存的是原始值,不是函数结果。一旦你在 WHERE 里对索引列调用函数(比如 DATE()、UPPER()、SUBSTR())或做运算(比如 age + 1 = 20),InnoDB 就没法直接拿索引节点去比对。
- ❌ 失效示例:
SELECT * FROM orders WHERE DATE(create_time) = '2025-04-18' - ✅ 改写方式:
SELECT * FROM orders WHERE create_time >= '2025-04-18 00:00:00' AND create_time - ⚠️ 注意:
key_len变小或为 0 是明显信号;EXPLAIN中key为空、type为ALL或index也说明没走预期索引
LIKE 查询以 % 开头(左模糊)
B+ 树索引按字典序存储,只能高效支持“已知前缀”的查找。LIKE '%张三' 或 LIKE '%张%' 没有确定起点,必须逐行匹配,自然跳过索引。
- ❌ 失效示例:
SELECT * FROM users WHERE name LIKE '%明' - ✅ 有效写法:
SELECT * FROM users WHERE name LIKE '明%'(满足最左前缀) - ? 补救方案:如果真要左模糊,且字段内容适合语义搜索,可加
FULLTEXT索引并用MATCH ... AGAINST,但注意仅限CHAR/VARCHAR/TEXT
隐式类型转换让索引“隐形”
字段是 VARCHAR,你传数字;字段是 INT,你传字符串——MySQL 会自动加转换函数(如 CAST()),等价于在索引列上做了函数操作。
MySQL 数据库管理技能,能够通过自然语言查询和管理数据库,支持 SELECT/INSERT/UPDATE/DELETE、表管理、备份恢复等操作。当用户提及 MySQL、数据库查询、建表或数据备份时使用此技能。
- ❌ 失效示例:
SELECT * FROM users WHERE phone = 13800138000(phone是VARCHAR) - ✅ 正确写法:
SELECT * FROM users WHERE phone = '13800138000' - ? 验证方法:看
EXPLAIN的Extra字段,若出现Using where; Using index是好的;若只有Using where且key为空,大概率是类型不匹配
联合索引没遵守最左前缀,或范围查询“截断”了后续列
联合索引 (a, b, c) 的结构本质是先按 a 排,a 相同时再按 b 排,a,b 都相同时才按 c 排。跳过 a 查 b,或在 b 上用 > 这类范围条件,c 就失去有序性,无法继续用于索引查找。
- ❌ 失效组合:
WHERE b = 2 AND c = 3(跳过a);WHERE a = 1 AND b > 10 AND c = 'x'(c不生效) - ✅ 有效组合:
WHERE a = 1 AND b = 2 AND c = 3;或WHERE a = 1 AND b BETWEEN 5 AND 15(c仍可做索引条件下推,但不能用于查找) - ? 关键观察点:
key_len值能告诉你实际用了索引的前几列。比如key_len = 8而整索引宽 12,说明只用到了前两列
真正难排查的,往往不是单个错误,而是多个条件叠加后优化器的综合判断——比如 OR 连接两个非同索引字段、NOT IN 包含大量值、或者 ORDER BY 字段不在索引覆盖范围内却要求避免 filesort。这些不会立刻报错,但会让 EXPLAIN 显示出意料之外的 type 和 Extra。










