唯一索引在 MySQL 中的核心作用是确保某列(或多个列组合)的值在整个表中不重复,从而保障数据的完整性与业务逻辑的正确性。它不是“可有可无”的优化项,而是在关键字段上必须考虑的数据约束手段。
什么时候必须加唯一索引?
以下场景一旦忽略唯一索引,极容易引发脏数据、业务异常甚至资损:
用户注册系统中的手机号或邮箱字段:防止同一手机号被反复注册,避免账号冲突和安全风险; 订单号、支付流水号、优惠券码等业务单号:这些本应全局唯一,若未加唯一约束,可能产生重复下单、重复发券等问题; 联合唯一约束用于多维唯一校验:例如(user_id, product_id)表示一个用户只能收藏某商品一次;(date, store_id)表示某门店每天只允许一条营业数据。如何创建唯一索引?
建表时或建表后都可添加,语法简洁明确:
建表时定义:CREATE TABLE t_user (id INT PRIMARY KEY, phone VARCHAR(11), UNIQUE KEY uk_phone (phone)); 已有表添加:ALTER TABLE t_user ADD UNIQUE INDEX uk_email (email); 联合唯一索引:ALTER TABLE t_fav ADD UNIQUE INDEX uk_uid_pid (user_id, product_id);注意:如果字段本身允许 NULL,MySQL 会把多个 NULL 视为不重复(即允许多个 NULL 值),这与部分数据库不同,需结合业务判断是否需要额外校验。
唯一索引和主键、普通索引的区别
三者定位不同,不能混用:
主键:非空 + 唯一 + 一个表仅一个,自动创建聚簇索引; 唯一索引:可为空、可多个、不强制作为主键,适合业务层的唯一性保障; 普通索引:不保证唯一性,仅加速查询,重复值完全允许。例如:用户表中 id 是主键,phone 是唯一索引,nickname 是普通索引——这样既满足主键要求,又防止手机号重复,还支持昵称模糊搜索。
遇到 Duplicate Entry 错误怎么办?
插入或更新时提示 Duplicate entry 'xxx' for key 'uk_xxx',说明违反了唯一约束。常见应对方式:
提前查重:SELECT 1 FROM t_user WHERE phone = '138...'; 再决定是否插入(注意并发下仍可能冲突,建议配合事务+重试或 INSERT IGNORE); 使用 INSERT IGNORE 忽略冲突行(适合日志类、上报类弱一致性场景); 使用 ON DUPLICATE KEY UPDATE 实现“存在则更新”,如更新最后登录时间; 应用层捕获 SQLSTATE '23000' 异常,返回友好提示(如“该手机号已被注册”)。