mysql> SELECT phone, COUNT(1) FROM User GROUP BY phone;
+-----------------+----------+
| phone | count(1) |
+-----------------+----------+
| NULL | 70 |
| | 40 | -- 空字串 ''
| +86-13390889711 | 1 |
| +86-13405053385 | 1 |
+-----------------+----------+
mysql> ALTER TABLE User ADD CONSTRAINT uk_phone UNIQUE (phone);
ERROR 1062 (23000): Duplicate entry '' for key 'uk_phone'
NULL 不是值,多個 NULL 允許進入唯一索引(InnoDB/MyISAM 均如此)'' 而非 NULL,導致大量重複空值SELECT phone, COUNT(*) FROM User GROUP BY phone;
SELECT COUNT(*) FROM User WHERE phone IS NULL; -- 70
SELECT COUNT(*) FROM User WHERE phone = ''; -- 40
UPDATE User SET phone = NULL WHERE phone = '';
-- Query OK, 40 rows affected
ALTER TABLE User ADD CONSTRAINT uk_phone UNIQUE (phone);
-- Query OK
-- 僅對非空值強制唯一
CREATE UNIQUE INDEX uk_phone_not_null ON User (phone) WHERE phone IS NOT NULL;
優雅解決「多 NULL/空值共存」且無需清洗歷史資料。
NULL,非業務必填勿設 NOT NULLNULL 而非 '',ORM 配置 empty_string_is_null=trueUPDATE ... SET col=NULL WHERE col=''SELECT col, COUNT(*) FROM t GROUP BY col HAVING COUNT(*)>1 AND col IS NOT NULL AND col<>'' 定期掃描潛在衝突唯一索引允許多 NULL,不允許多 ''。統一空值語義為 NULL 是根治之道。MySQL 8.0.13+ 可用 WHERE phone IS NOT NULL 部分唯一索引優雅繞過歷史包袱。