mysql中is null和is not null能否走索引取决于优化器成本估算,核心是null值占比及索引前提:字段允许null、有合规索引、最左前缀匹配;低null占比时is null常走索引,高非null占比时is not null易退化为全表扫描。

MySQL 中 `IS NULL` 和 `IS NOT NULL` 能否走索引,不取决于语法本身,而取决于优化器对查询成本的判断——核心是 NULL 值在该列中的实际分布比例,以及是否满足索引使用的基本前提(如字段有索引、查询方式匹配等)。
IS NULL 什么时候能走索引?
当列上有索引,且该列中 NULL 值占比不高(即选择性较好)时,优化器通常会选择走索引。
- InnoDB 的 B+ 树索引明确存储 NULL 值,并将其视作“最小值”,放在索引最左侧,因此可以定位扫描
- 例如:某列建了索引,3 万行中只有约 1500 行为 NULL(占比 5%),
WHERE col IS NULL很可能走ref或range类型索引扫描 - EXPLAIN 显示
key非 NULL、type为ref或range,就说明用了索引
IS NOT NULL 为什么有时不走索引?
这不是语法限制,而是优化器权衡后的主动放弃——当非 NULL 值占绝大多数时,“索引查找 + 回表”总成本可能高于直接全表扫描。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 比如:3 万行中 28500 行非 NULL(占比 95%),
WHERE col IS NOT NULL很可能触发type: ALL,即全表扫描 - 原因在于:索引扫描需先查索引页,再根据主键回表取完整行;若要回表近 3 万次,I/O 开销远超顺序读全表
- 但若非 NULL 值是少数(比如只占 5%),优化器就会转而用索引快速定位这少量记录
哪些情况会让它们“看起来不走索引”?
不是条件本身失效,而是执行环境或写法触发了隐性限制:
-
索引列定义为 NOT NULL:此时
IS NULL永远无结果,优化器可能直接跳过索引甚至忽略该条件;IS NOT NULL变成恒真,也可能退化为全表扫描 - SELECT * + 索引非覆盖:若索引不能覆盖查询所需所有字段,就要回表。回表次数太多时,优化器倾向放弃索引
-
复合索引中前导列不参与过滤:例如索引是
(a, b),只写WHERE b IS NULL,无法利用该索引(最左前缀原则) - 统计信息过期:ANALYZE TABLE 未更新,优化器基于错误基数估算,可能误判成本
如何确认和优化?
别凭经验猜,用工具验证并针对性调整:
- 始终用
EXPLAIN FORMAT=TRADITIONAL或FORMAT=JSON查看真实执行计划,重点关注key、type、rows、filtered - 检查 NULL 分布:
SELECT COUNT(*) cnt, COUNT(col) non_null_cnt, COUNT(*) - COUNT(col) null_cnt FROM t; - 若业务允许,把允许 NULL 的索引列改为
NOT NULL DEFAULT ''或0,既提升索引稳定性,也节省存储空间 - 高频
IS NULL查询可考虑单独建覆盖索引,例如INDEX idx_col_null (col) INCLUDE (id, name)(MySQL 8.0.13+ 支持函数索引或前缀覆盖变通)










