一、UNIQUE INDEX语法
普通索引只负责加速查询,而唯一索引有两个必须同时满足的功能:
- 唯一性约束:强制指定列(或列组合)的数据不能重复(这是它的核心使命)。
- 加速查询:底层依然是 B+Tree 结构,查询效率和普通索引一样快。
一句话区分:
- 普通索引:允许重复,只管快。
- 唯一索引:禁止重复,又快又严。
二、两种创建时机
根据业务场景,唯一索引的创建分为 “建表时” 和 “建表后” 两种,语法你在图中都见过,这里做标准化梳理。
1、建表后添加(适用于已有表)
这是你在维护系统时最常用的方式,使用 CREATE UNIQUE INDEX。
-- 语法
CREATE UNIQUE INDEX 索引名 ON 表名(列名);
-- 例子:给租户表的 email 加唯一索引
CREATE UNIQUE INDEX idx_tenant_email ON tenant(email);
2、建表时定义(适用于新系统设计)
这种方式更优雅,通常直接写在 CREATE TABLE 里。有两种写法:
写法 A:单列唯一(简洁版)
CREATE TABLE tenant (
id INT PRIMARY KEY,
email VARCHAR(50) UNIQUE -- 直接在列后加 UNIQUE
);
写法 B:多列复合唯一(推荐)
这种方式可以给索引命名,便于后续管理(如删除)。
CREATE TABLE tenant_user (
id INT PRIMARY KEY,
tenant_id INT,
username VARCHAR(50),
-- 命名为 uk_tenant_user,保证 (tenant_id, username) 组合唯一
CONSTRAINT uk_tenant_user UNIQUE (tenant_id, username)
);
三、 核心场景:单列唯一 vs 复合唯一
1、 单列唯一(全局唯一)
场景:租户的邮箱。
逻辑:在整个 tenant 表中,任何两行的 email 都不能一样。
效果:插入 @123.com 后,再插一次就报错 1062 Duplicate entry。
2、复合唯一(局部唯一)
场景:租户下的用户名(tenant_id + username)。
逻辑:允许用户名重复(如 A 租户有个 admin,B 租户也可以有),但同一个租户内不能重复。
效果:
(1, 'admin')和(2, 'admin')→ 可以插入(租户不同)。(1, 'admin')和(1, 'admin')→ 报错(租户和用户名都相同)。
四、闭环操作(配合已学的命令)
学完创建,必须要和你之前学的 SHOW 和 DROP 联动,形成完整的操作闭环。
| 操作 | 命令 | 关键观察点 |
|---|---|---|
| 查看 | SHOW INDEXES FROM tenant; | Non_unique 列的值为 0(表示唯一)。 |
| 删除 | DROP INDEX idx_tenant_email ON tenant; | 唯一索引也是索引,删除语法和普通索引完全一样。 |
| 验证 | INSERT INTO ... | 重复插入会抛出 1062 错误,这是最好的验证方式。 |
五、 避坑指南
1、NULL 值的特殊性:
唯一索引允许插入 多个 NULL(因为 NULL 不等于 NULL)。如果不想要这种情况,需要将列设为NOT NULL。
2、主键 vs 唯一索引:
主键(Primary Key):一张表只能有一个,不允许 NULL。
唯一索引:一张表可以有多个,允许 NULL(除非列设为 NOT NULL)。
3、复合索引的最左匹配:
对于复合唯一索引(a,b),查询WHERE a =1可以命中索引,但where b =2 不能。