mysql中is null查询难走索引,因b+树对null特殊处理致页碎片多、优化器常弃用;可用coalesce函数索引或tinyint标志位拆分优化,但需权衡使用场景。

MySQL 中含大量 NULL 值的字段,如果直接建普通 B+ 树索引,不仅浪费空间,还可能降低查询效率——因为 NULL 在 B+ 树中被特殊处理(不参与排序比较、单独存储为标记位),导致页内碎片多、页利用率低、范围扫描跳过大量无效记录。
为什么 IS NULL 查询走不了普通索引?
MySQL 的二级索引默认不存储 NULL 值(InnoDB 引擎下,NULL 被编码为一个特殊字节,但索引项仍会生成;不过优化器常因统计信息不准或成本估算偏差而放弃使用该索引)。尤其当表中 NULL 占比超过约 70%,优化器大概率判定全表扫描更便宜。
-
EXPLAIN显示type: ALL或key: NULL,即使字段上有索引 - 执行
SELECT ... WHERE col IS NULL时,实际执行计划未用到col上的索引 -
SHOW INDEX FROM tbl查看Null列为YES,说明该列允许NULL,但这不等于索引对NULL友好
用 COALESCE() + 函数索引强制覆盖 NULL
MySQL 5.7+ 支持函数索引(需开启 innodb_large_prefix=ON,且行格式为 DYNAMIC 或 COMPRESSED),可将 NULL 显式转为可控值再索引。核心思路是:让所有值都“有定义”,避免索引项空洞。
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
- 建函数索引:
CREATE INDEX idx_col_notnull ON tbl ((COALESCE(col, -999999999)));
- 查
NULL时改写为等值查询:WHERE COALESCE(col, -999999999) = -999999999 - 选替代值要注意:必须不在业务数据范围内,且类型兼容(如
INT字段用极大负数,VARCHAR用'__NULL__') - 该方式使索引叶节点完全紧凑,无
NULL标记开销,页分裂概率下降
改用 TINYINT 标志位 + 单独索引更省空间
如果字段语义上就是“有/无”二元状态(比如 deleted_at、processed_time),与其存大量 NULL,不如拆成布尔标志 + 实际值两列。这是最彻底的空间与查询优化。
- 新增
is_col_present TINYINT(1) DEFAULT 0,并建索引:INDEX idx_is_col_present (is_col_present) - 原字段改为允许
NOT NULL,仅在is_col_present = 1时才有效 - 查询
IS NULL等价于WHERE is_col_present = 0,走索引非常高效 - 单个
TINYINT占 1 字节,远小于NULL在索引中的隐式标记 + 额外指针开销
真正关键的是别把 NULL 当“免费占位符”——它在索引里既不省空间,也不提速。函数索引和标志位拆分不是银弹,得看字段是否高频用于 IS NULL 过滤;若只是偶尔补全,加个 OR col IS NULL 反而破坏索引合并,这时不如接受全扫,或者考虑分区裁剪。










