bigywater.tech
MySQL / InnoDB · 24

唯一索引与 NULL:为什么两个 NULL 可以同时存在

往一个UNIQUE列里连续插入3个NULL,全部成功;再插入两个相同的非NULL值,第二次立刻报错——验证唯一索引对NULL和非NULL值是两套判断标准。

3个NULL共存
全部插入成功,无冲突
非NULL严格判重
第二次插入立刻报错
NULL不参与比较
SQL标准规定的底层原因

做的事:往唯一索引列里连续塞3个NULL

唯一索引的作用是"不允许重复值",NULL算不算重复。

代码CREATE TABLE t10 (id INT PRIMARY KEY AUTO_INCREMENT, email VARCHAR(100), UNIQUE KEY uq_email(email)); INSERT INTO t10 (email) VALUES (NULL); INSERT INTO t10 (email) VALUES (NULL); INSERT INTO t10 (email) VALUES (NULL);

验证:3次NULL,全部插入成功

按理说是同一个唯一索引,3次一样的值,却没有一次报错。

结果SELECT * FROM t10; → 1 NULL → 2 NULL → 3 NULL (3行全部插入成功,没有任何唯一索引冲突)

验证了MySQL对UNIQUE约束的一条特殊规则:NULL不参与唯一性比较。SQL标准里,任何值跟NULL做比较(包括NULL跟NULL比)结果都是"未知",不是"真",所以数据库认为"两个NULL"不构成重复——多少个NULL都能塞进同一个唯一索引列。

验证:非NULL的重复值,立刻被拒绝

同一个索引,换成相同的具体值。

结果INSERT INTO t10 (email) VALUES ('a@x.com'); INSERT INTO t10 (email) VALUES ('a@x.com'); 报错: Duplicate entry 'a@x.com' for key 't10.uq_email'
同一个唯一索引,对NULL和非NULL值执行的是两套不同的判断标准:非NULL值严格比较相等性,一旦发现重复立刻拒绝;NULL则被当作"值未知",天然不会跟任何值(包括另一个NULL)判定为相等,所以能反复插入。这也是为什么用UNIQUE实现"某字段有值就必须唯一,没有值就随便"(比如email选填但一旦填了不能重复)这类业务需求时,不需要额外处理——UNIQUE约束本身就自带了这个行为。但也要小心一个的陷阱:如果误以为UNIQUE能限制"最多只有一行是NULL",会踩坑——它完全不限制NULL的数量。

分步演示:唯一索引对NULL的特殊对待

每一步都是本文上面用MySQL跑出来的原始结果。

NULL不参与唯一性比较,非NULL严格比较
这一步新验证的结果

    本文用到的工具

    • 本机 MySQL 26.7.0(InnoDB),UNIQUE KEY约束列
    • 验证NULL和非NULL在唯一索引下完全不同的判断标准
    京ICP备2026067502号-1京公网安备11010502063487号