首页/数据/SQL 速查/唯一索引与普通索引怎么选
性能与执行计划72 条

唯一索引与普通索引怎么选

唯一索引承担业务约束、等值查找命中即停;普通索引允许重复值、用于支撑查询。约束真与查询快是两件事。

SQL 速查数据更新于 2026-10-13

两者解决的不是同一件事

唯一索引承担业务约束(值不允许重复),并让等值查找一旦命中就能停止;普通索引只负责支撑查询与排序,允许重复值。选型时先问「这个唯一性是不是业务硬要求」,再考虑查询性能——为了提速把普通索引改成唯一索引,通常是本末倒置。

基本信息

唯一索引用途业务约束加等值查找
普通索引用途支撑查询与排序,允许重复值
查找差异唯一索引命中即可停止;普通索引还要继续检视重复值
写入成本唯一索引插入要做冲突检查,并发冲突需业务处理
NULL 语义两库默认允许多个 NULL;PostgreSQL 15+ 可用 NULLS NOT DISTINCT 改变

典型使用场景

  • 注册邮箱、手机号必须唯一
  • 订单号、流水号不允许重复
  • 状态列、外键列只用于查询,建普通索引即可
  • 复合唯一键表达「同一用户同一类型只能有一条」
  • 用唯一索引的冲突来探测重复写入,配合 upsert 做幂等

示例

示例
-- 业务唯一:注册邮箱不允许重复
ALTER TABLE users ADD UNIQUE KEY uk_email (email);

-- 复合唯一:同一用户同一渠道只能绑定一条
ALTER TABLE bindings ADD UNIQUE KEY uk_user_channel (user_id, channel);

-- 仅查询支撑:允许重复值
ALTER TABLE orders ADD INDEX idx_user_created (user_id, created_at);

-- PostgreSQL:唯一约束会创建对应的唯一索引
ALTER TABLE users ADD CONSTRAINT uk_users_email UNIQUE (email);

两种索引对照

维度唯一索引普通索引
重复值不允许(NULL 除外)允许
等值查找命中即停命中后还要继续检视
写入成本额外做冲突检查,可能抛唯一冲突只维护索引结构
与约束关系通常就是约束的载体纯性能对象
删除影响可能一并移除业务约束只影响性能
唯一性由业务决定,不能为了提速把普通索引改成唯一索引:列上本来就有重复值,约束建不起来,语义也不对。
唯一索引的 NULL 语义两库默认一致:多个 NULL 互不冲突。PostgreSQL 15 起可用 NULLS NOT DISTINCT 把 NULL 也纳入唯一性判断,需要这种语义时用它,而不是在应用层兜。

易错点

  • 把查询优化寄托在唯一索引上:唯一性由业务决定,本来允许重复的列不能改成唯一索引
  • 用唯一索引当并发互斥:插入冲突会直接报错,需要配套重试或 upsert 逻辑,否则请求成批失败
  • 以为唯一索引会拦住重复 NULL:默认多个 NULL 互不冲突,需要严格唯一要配合 NOT NULL
  • 直接删除唯一索引:唯一性保证随之消失,重复数据可能被静默写入
  • 复合唯一键的列序与查询不匹配:虽然能当普通索引用,但最左前缀不对就帮不上过滤与排序

数据来源与参考

  • MySQL 8.0 Reference Manual · How MySQL Uses Indexes
  • PostgreSQL Documentation · Unique Indexes
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌