
从 InnoDB 的角度看,普通索引的职责非常单一:
为某个访问模式提供一条更低成本的查找路径
CREATE INDEX idx_xxx ON t(col);
其核心特征是:
换句话说:
**普通索引解决的是“怎么更快读到数据”,而不是“这份数据对不对”**。
CREATEUNIQUE INDEX uk_xxx ON t(col);
在 InnoDB 内部,唯一索引多承担了一层职责:
也就是说:
**UNIQUE 是一种“参与写入流程的索引”**。
从架构角度看,这意味着:
维度 | INDEX | UNIQUE |
|---|---|---|
是否建立 B+Tree | 是 | 是 |
是否约束数据 | 否 | 是 |
是否参与写入校验 | 否 | 是 |
是否承担数据一致性 | 否 | 是 |
**UNIQUE 的本质不是“更严格的索引”,而是“数据库层的数据规则”**。
当某字段仅有普通索引时:
INSERTINTO t(col) VALUES ('A');
INSERTINTO t(col) VALUES ('A');
在数据库视角:
这意味着:
从 DBA 视角看,这类表的风险是:
**数据错误不是“偶发 Bug”,而是“结构性必然”**。
当字段被 UNIQUE 约束:
INSERTINTO t(col) VALUES ('A');
INSERTINTO t(col) VALUES ('A');
-- Duplicate entry
InnoDB 在写入路径中完成:
这意味着:
UNIQUE 是数据库参与业务正确性的最小、也是最可靠方式。
在 MySQL 中:
这在 DBA 设计阶段非常关键:
<span>UNIQUE + NOT NULL</span>否则:
表结构与业务语义天然不一致
从执行计划角度看:
优化器层面:
<span>= 条件</span> 最多返回一行但在绝大多数 OLTP 场景下:
查询性能差异可以忽略,不应作为选型依据。
这意味着:
但从架构视角:
这是为“数据绝对正确”付出的合理成本。
场景 | INDEX | UNIQUE |
|---|---|---|
并发写入 | 可能写穿 | 强一致 |
幂等支持 | 需业务实现 | 数据库天然支持 |
回放 / 重试 | 高风险 | 安全 |
这也是为什么在:
这类字段上,不用 UNIQUE 基本等同于架构缺陷。
从 DBA 视角,三者职责清晰分层:
PRIMARY KEY = 唯一 + 非空 + 聚簇
它承担的是:
不应滥用为业务约束。
类型 | 唯一 | NULL | 角色 |
|---|---|---|---|
PRIMARY KEY | 是 | 否 | 行身份 |
UNIQUE | 是 | 是 | 业务规则 |
INDEX | 否 | 是 | 性能工具 |
ADDUNIQUE INDEX uk_col(col);
ADD INDEX idx_col(col);
这是一种“功能完全重叠但成本翻倍”的设计错误。
凡是“不能错”的数据,一定要数据库兜底。
这些字段:
一个成熟系统的数据正确性,应该“写死在表结构里”,而不是“祈祷代码不出错”。