不等号查询不会让索引完全失效,但会破坏其可预测过滤能力,导致优化器倾向全表扫描;>、
不等号查询(
!=、、>、)本身不会让索引“完全失效”,但会让优化器放弃使用索引做精确查找,转而考虑范围扫描或全表扫描——关键在于它破坏了索引的“可预测过滤能力”。为什么
!=通常触发全表扫描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 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—— 仍可能触发索引合并(type: index_merge),但不如单索引稳定- 对高频排除场景,改用覆盖索引减少回表开销:
SELECT id FROM t WHERE status != 'done',若status是索引前缀,且只查id,可能走type: index- 数据量可控时,业务层拆分:先查出要排除的 ID 集合,再用
NOT IN (…)(注意空值和 NULL 安全)最易被忽略的一点:优化器是否走索引,最终取决于
statistics是否准确。执行ANALYZE TABLE后再看EXPLAIN,结果可能完全不同——别只信一次测试。












