不等号查询不会让索引完全失效,但会破坏其可预测过滤能力,导致优化器倾向全表扫描;>、< 可走范围扫描但截断复合索引后续列;替代方案需结合执行计划验证。

不等号查询(!=、<>、>、<)本身不会让索引“完全失效”,但会让优化器放弃使用索引做精确查找,转而考虑范围扫描或全表扫描——关键在于它破坏了索引的“可预测过滤能力”。
为什么 != 通常触发全表扫描
MySQL 的 B+ 树索引本质是为等值匹配和有序范围设计的。!= 条件无法定位一个连续的物理区间,而是要求“排除某点后取其余全部”。优化器估算发现:如果目标值占比小(比如 1%),走索引再回表可能比直接全表扫描更慢;如果占比大(比如 95%),全表扫描反而更省 I/O。它倾向于选择成本更低的路径,而这个成本判断常导向 type: ALL。
-
EXPLAIN中key字段为空或非预期索引,type为ALL或index,是典型信号 - 不是绝对不走索引:当表极小、或该列有极高区分度且优化器统计准确时,
!=也可能走索引,但不可依赖 -
NOT IN和NOT EXISTS同理,本质也是集合排除逻辑
> 和 < 为何只“部分失效”
它们能利用 B+ 树的有序性做范围扫描(type: range),但会截断后续索引列的使用——尤其在复合索引中。
- 索引
(a, b, c)上执行WHERE a = 1 AND b > 10:能用到a和b,但c列的索引失效(c不再有序) - 执行
WHERE a > 1:只能用到a,b和c完全不可用 - 注意:
>=和<=行为一致,不改变范围截断逻辑
真正要警惕的是“隐式范围化”的写法
有些看似安全的写法,实际被优化器转成了等效的不等号逻辑,悄悄绕过索引。
-
WHERE col NOT BETWEEN 10 AND 20≡col < 10 OR col > 20,大概率全表扫描 -
WHERE col != 10 OR col IS NULL:OR引入额外分支,即使col有索引,也可能退化 -
WHERE col IN (1,2,3,4,5,6,7,8,9,11):当列表太长,优化器可能放弃range改走ALL
能用但必须小心的替代方案
没有银弹,只有权衡。以下方式可能保留索引,但需验证执行计划:
- 用两个方向的范围拼出“不等于”:
WHERE col < 10 OR col > 10—— 仍可能触发索引合并(type: index_merge),但不如单索引稳定 - 对高频排除场景,改用覆盖索引减少回表开销:
SELECT id FROM t WHERE status != 'done',若status是索引前缀,且只查id,可能走type: index - 数据量可控时,业务层拆分:先查出要排除的 ID 集合,再用
NOT IN (…)(注意空值和 NULL 安全)
最易被忽略的一点:优化器是否走索引,最终取决于 statistics 是否准确。执行 ANALYZE TABLE 后再看 EXPLAIN,结果可能完全不同——别只信一次测试。


















