is null 能走索引需同时满足三条件:字段允许 null、索引结构合规(单列或联合索引中最左连续等值后的首列)、优化器成本估算认为值得;否则跳过索引选择或退化为全表扫描。

能走索引,但前提是字段允许 NULL、索引结构匹配,且优化器认为“值得用”——不是语法问题,是成本权衡结果。
字段定义为 NOT NULL 时,IS NULL 根本不会触发索引
这是最容易被忽略的硬性前提。如果列定义为 NOT NULL,MySQL 优化器在解析阶段就直接判定 col IS NULL 永远为 false,连索引选择环节都跳过。
- 检查方式:
SHOW CREATE TABLE table_name看目标列是否含NOT NULL - 常见错误现象:
EXPLAIN显示key=NULL且type=ALL,但你确信建了索引——大概率是字段定义错了 - 修复动作:改列定义(
ALTER TABLE t MODIFY col INT NULL)或业务层避免查一个不可能为 NULL 的字段
联合索引中 IS NULL 只对“最左连续等值链之后的第一列”生效
InnoDB 的 B+ 树索引不支持跳过前导列,IS NULL 在联合索引里的行为严格受限于最左前缀规则。
- 索引
(a, b, c)下,WHERE a = 1 AND b IS NULL可走索引(a提供等值定位,b在子树内扫描 NULL) - 但
WHERE b IS NULL或WHERE a IS NULL AND b = 1基本不走——前者无前导等值,后者a IS NULL无法作为有效起始点(NULL 不参与排序锚定) - 注意:
a IS NULL即使单独建了单列索引,在联合索引里也**不能**作为最左列用于范围扫描
优化器是否选索引,取决于 NULL 比例和回表代价
即使满足前两个条件,IS NULL 是否真走索引,最终由成本模型决定。它会比较“索引扫描 + 回表”和“全表扫描”的预估开销。
- 高 NULL 比例(如 90%):
IS NULL很可能走索引(只扫左侧少量页),IS NOT NULL则大概率退化为全表扫描(扫 90% 行,随机 IO 太贵) - 低 NULL 比例(如 1%):
IS NULL扫的行少,走索引;IS NOT NULL反而更可能走索引(因为要扫的非 NULL 行集中分布在索引右侧,range 扫描效率高) - 验证方法:
EXPLAIN SELECT * FROM t WHERE col IS NULL后看rows和key;再对比加FORCE INDEX (idx_col)后rows是否显著下降
别信“IS NULL 一定不走索引”的老经验
MySQL 5.7 起,InnoDB 把 NULL 视为最小值存入 B+ 树最左端,8.0 更稳定。但这个机制只在单列二级索引或联合索引的合规位置才真正起效。
- 主键/唯一索引中不允许 NULL,所以
IS NULL在这类索引上天然无效 - 函数索引、表达式索引(如
INDEX ((col IS NULL)))是绕过限制的方案,但需业务层配合写法统一 - ORM 自动生成的
IS NULL查询常因包装逻辑(如COALESCE(col, '') IS NULL)导致隐式转换,让优化器无法识别原始谓词
真正卡住的从来不是语法本身,而是字段定义、索引结构、数据分布、优化器估算这四者的耦合。每次遇到 IS NULL 不走索引,先跑 EXPLAIN + SHOW INDEX + SHOW CREATE TABLE 三连,比查文档更快定位真实瓶颈。











