一篇吃透 MySQL 唯一索引:创建、验证、避坑全攻略

4 阅读3分钟

一、UNIQUE INDEX语法

普通索引只负责加速查询,而唯一索引有两个必须同时满足的功能:

  1. 唯一性约束:强制指定列(或列组合)的数据不能重复(这是它的核心使命)。
  2. 加速查询:底层依然是 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')报错(租户和用户名都相同)。

四、闭环操作(配合已学的命令)

学完创建,必须要和你之前学的 SHOWDROP 联动,形成完整的操作闭环。

操作命令关键观察点
查看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 不能。