隐式转换和函数调用均导致索引失效:前者因类型不匹配触发cast操作,后者因索引列参与计算或函数参数而无法匹配b+树原始值;联合索引中范围查询使右侧列失效,is not null及!=也常致全表扫描。

隐式转换导致索引不走 key
MySQL 在字段类型与查询值类型不一致时,会自动做隐式转换——这等价于在索引列上加了函数,直接让索引失效。
常见现象:EXPLAIN 中 key 为 NULL,type 是 ALL 或 index,且 Extra 出现 Using where(说明全表扫描后才过滤)。
- 字符串字段没加引号:
WHERE phone = 13800138000(phone是VARCHAR)→ MySQL 转成CAST(phone AS SIGNED) - 数字字段加了引号:
WHERE id = '123'(id是INT)→ MySQL 转成CAST('123' AS SIGNED) - 不同字符集列 JOIN 或比较,比如
utf8和utf8mb4字段直接=,也会触发转换
排查方法:用 SHOW WARNINGS 看优化器是否提示 Implicit type conversion;或在 EXPLAIN FORMAT=TREE 中观察是否出现 cast 操作。
WHERE 中调用函数让索引失效
只要索引列出现在函数参数里、表达式左侧或被计算,MySQL 就无法用 B+ 树快速定位值——因为索引里存的是原始值,不是函数结果。
典型错误写法:
-
WHERE DATE(create_time) = '2023-01-01'→create_time上的索引完全无效 -
WHERE UPPER(name) = 'LUCY'→ 即使name有索引,也扫全表 -
WHERE price * 1.2 > 100→price列参与运算,索引失效
正确改写方向是把计算移到右侧或改用范围条件:
WHERE create_time >= '2023-01-01' AND create_time 100 / 1.2
注意:LIKE 'xxx%' 可走索引,但 LIKE '%xxx' 或 LIKE '%xxx%' 不行。
联合索引中范围查询导致后续列失效
复合索引 (a, b, c) 不是“部分生效”,而是“断点之后全失效”。一旦某列用了范围条件(>、>=、、<code>BETWEEN、LIKE 'xxx%'),它右边所有列的索引能力就归零。
-
WHERE a = 1 AND b > 10 AND c = 5→c的条件不会走索引,仅a和b有效 -
WHERE a > 1 AND b = 2→b完全失效,只用到a -
WHERE a = 1 AND b LIKE 'x%' AND c = 5→c失效(LIKE 'x%'属于范围操作)
这不是 bug,是 B+ 树结构决定的:范围扫描后,数据已不再有序,无法再按 c 二分查找。若业务强依赖 c 过滤,得考虑覆盖索引或拆分查询。
IS NOT NULL 和 != 的实际影响
IS NOT NULL 在大多数情况下会让索引失效,而 IS NULL 反而可以走索引(前提是该列允许 NULL 且有对应统计信息)。
-
WHERE status IS NOT NULL→ 通常退化为全表扫描,尤其当 NULL 值占比很小时 -
WHERE status != 'done'或status 'done'→ 优化器大概率放弃索引,因需排除大量行,不如直接扫
例外情况存在,比如该列基数极高、非 NULL 值极少,且优化器评估成本更低时可能仍用索引——但不能依赖。更稳的写法是用 IN 列出明确值,或补上 NOT NULL 约束后建索引。
真正容易被忽略的是:这些失效点往往叠加出现。比如一个 WHERE 同时含隐式转换 + 函数 + OR,EXPLAIN 看起来像“没走索引”,但实际根因可能是最前面那个类型转换——得逐项排除,不能只盯最后一条条件。











