ALTER TABLE ADD UNIQUE 失败主因是列存重复值,MySQL 5.7+ 严格校验;需先查重、清理或改用组合索引;显式命名约束更易维护;大表应优先用 ALGORITHM=INPLACE;NULL 在唯一索引中不互斥,业务需额外处理。

直接执行 ALTER TABLE ADD UNIQUE 报 Duplicate entry
MySQL 5.7+ 默认开启严格模式,加唯一索引时会**全表扫描并校验每一行**,只要发现任意两行在目标列上值相同(包括空字符串''和NULL混用),就立即中止并报错:Duplicate entry 'xxx' for key 'col'。这不是语法错误,是数据层拒绝——它不会“自动去重”或“跳过冲突”,也不会像旧版 MySQL 那样支持 IGNORE 关键字。
查重必须手动做,不能靠建索引时“顺带清理”
建索引前不查重,等于把问题留给线上时刻。常见疏漏点:
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
- 只查
SELECT col FROM t GROUP BY col HAVING COUNT(*) > 1,但没检查NULL和空字符串是否被业务当成同一语义(比如手机号字段存了NULL和'',两者在唯一索引里不互斥,但业务上都代表“未填写”) - 用
DELETE ... JOIN去重时没确认主键是否存在或是否为自增——若无主键,t1.id 这类条件会失效 - 误以为组合索引能绕过单列重复:比如对
(a, b)加联合唯一索引,但a列本身已大量重复,这不影响建索引成功;可一旦你后续只插入a值而b为NULL,仍可能因多条(x, NULL)导致逻辑重复
CREATE UNIQUE INDEX 和 ALTER TABLE ADD UNIQUE 没本质区别
两者最终都创建同类型约束,差异仅在命名控制和语法习惯:
- 不显式命名时,
ALTER TABLE ADD UNIQUE (col)自动生成索引名如col;CREATE UNIQUE INDEX idx_col ON t(col)可自定义,后续DROP INDEX idx_col ON t更清晰 - 都受
ALGORITHM=INPLACE支持,但大表仍会在最后阶段加元数据锁(MDL),写入会短暂阻塞;别指望“完全不锁” - 若表已分库分表,唯一索引只在单库内生效——跨库的相同值不会触发冲突,这是架构层限制,不是 SQL 层能解决的
NULL 在唯一索引里“不参与比较”是个坑
MySQL 允许多个 NULL 值共存于唯一索引列,标准 SQL 也如此。但这常导致误判:
- 业务代码把
NULL当作“未设置”,把空字符串''当作“用户填了空”,结果两者都被允许插入,且都不违反唯一性——但查询时WHERE col = '' OR col IS NULL可能捞出多条“逻辑重复”记录 - 若字段语义上“空值也算一种值”(比如身份证号为空必须唯一标识“未知”),唯一索引本身无法满足,得靠应用层写前校验,或加触发器/生成列兜底
- 建索引前用
SELECT COUNT(*) FROM t WHERE col IS NULL单独统计NULL数量,比混在GROUP BY里更直观
Duplicate entry 'admin' 就急着删,结果发现是测试数据和正式数据混在一张表里——先分清环境,再动数据。

















