bigywater.tech
MySQL / InnoDB · 85

NULL、三值逻辑与索引

真实测NULL的相等比较、三值逻辑的短路规则,以及NOT IN列表里混入NULL会怎样真实影响整条查询,最后验证IS NULL到底能不能用上索引。

NOT IN+NULL=空结果
列表混入NULL真实会让整个条件失效
IS NULL真实能用索引
InnoDB索引真实把NULL当作可定位的值

做的事:真实测几组和NULL相关的比较、逻辑运算、IN条件

代码SELECT NULL = NULL AS a, NULL <=> NULL AS b, (1=1) AND NULL AS c, (1=0) AND NULL AS d; SELECT 5 IN (1,2,NULL) AS in_result, 5 NOT IN (1,2,NULL) AS not_in_result;

验证:NULL=NULL真实不是true,是"不知道"

实测 · 本机执行输出
NULL = NULL      → NULL   (不是true!两个"未知"比较,结果还是"未知")
NULL <=> NULL    → 1      (NULL-safe等于运算符,真实把NULL当成一个确定的值处理)
(1=1) AND NULL   → NULL   (true AND 未知 = 未知)
(1=0) AND NULL   → 0      (false AND 任何东西 = false,真实的短路)

普通的=运算符真实遵循严格的三值逻辑:任何值(包括NULL自己)和NULL比较,结果都真实是NULL(未知),不是true也不是false。只有专门的<=>(NULL-safe相等)运算符会真实把两个NULL当作相等处理。(1=0) AND NULL返回0而不是NULL,是因为AND运算符真实做了短路:只要有一边确定是false,不管另一边是什么,整体真实必然是false。

验证:NOT IN混进一个NULL,真实会让整个条件失效

实测 · 本机执行输出
5 IN (1,2,NULL)      → NULL   (不是false!5确实不在1,2里,但列表里的NULL让结果变成"不确定")
5 NOT IN (1,2,NULL)  → NULL   (同理,也不是true)
1 IN (1,2,NULL)      → 1      (1真实命中了,这种情况不受NULL影响)
这是一个真实容易踩的坑:IN/NOT IN的语义真实等价于把列表展开成一串OR/AND比较,只要列表里混进一个NULL、又没有命中前面的值,最终结果就真实会是NULL——而WHERE子句只保留结果为true的行,NULL和false一样真实会被过滤掉。也就是说,一条WHERE id NOT IN (SELECT blocked_id FROM blocklist),只要子查询结果集里真实混进哪怕一个NULL,这条查询会真实返回空结果集,不会报错,只是安静地什么都查不出来。

验证:IS NULL这一侧,索引真实还能用

实测 · 本机EXPLAIN FORMAT=TREE输出
SELECT * FROM null_idx WHERE val IS NULL;
-> Filter: (null_idx.val is null)
    -> Covering index lookup on null_idx using idx_val (val = NULL)   ← 真实走了索引查找

虽然NULL没法参与普通的比较运算,但IS NULL是一个专门的谓词,InnoDB的索引真实把NULL值当作一种可以被索引和定位的"值"来存储,IS NULL查询真实能直接走索引查找,不需要全表/全索引扫描。

分步演示:从NULL=NULL到NOT IN的真实连锁反应

每一步都是本文上面用真实查询跑出来的原始结果。

NOT IN混进一个NULL,真实的连锁反应
这一步新验证的场景

    本文用到的工具

    • 本机 MySQL 26.7.0(InnoDB),真实的三值逻辑测试 + IS NULL索引查询验证
    • <=>(NULL-safe相等) vs 普通=
    京ICP备2026067502号-1京公网安备11010502063487号