MySQL 普通索引和唯一索引在查询性能上几乎没有区别,选择的核心依据是业务是否需要数据库层保障数据唯一性。普通索引在写入场景下性能略高,因为能利用 Change Buffer 减少磁盘 I/O,而唯一索引因需校验唯一性无法使用该机制。
先说结论:查询性能差异可忽略,选型应优先保障数据完整性,除非写入瓶颈明确且业务层已兜底唯一性。
- 适合:业务字段绝对不允许重复的场景,如身份证号、订单号、手机号。
- 重点看:写入性能敏感且数据离散度高时,普通索引可利用 Change Buffer 提升吞吐。
- 别忽略:唯一索引允许存入多个 NULL 值,需配合 NOT NULL 约束使用。
命令速用版
创建普通索引和唯一索引的标准 SQL 语法如下,根据业务需求选择执行:
CREATE INDEX idx_normal ON table_name (column_name);
CREATE UNIQUE INDEX idx_unique ON table_name (column_name);
若字段要求非空且唯一,建议 combined 约束:
ALTER TABLE table_name MODIFY column_name VARCHAR(255) NOT NULL;
为什么会这样
查询性能差异微乎其微,核心区别在于写入时的 Change Buffer 机制。
InnoDB 数据按页读写,默认页大小 16KB,查询时普通索引多一次判断下一条记录的操作,但在内存中该 CPU 开销可忽略不计。写入时,若目标数据页不在内存中,普通索引可将变更记录到 Change Buffer 中,避免立即读取磁盘;唯一索引必须先将数据页读入内存以校验唯一性,无法使用 Change Buffer,导致随机磁盘 I/O 增加。
分步处理
1. 确认业务语义:判断字段是否在逻辑上绝对唯一,如用户身份证、系统订单号。
2. 评估写入压力:若为高并发写入场景且数据离散,普通索引能显著减少磁盘 I/O。
3. 检查空值约束:若业务要求字段必须有值,需显式添加 NOT NULL 约束,避免唯一索引允许多个 NULL 的陷阱。
4. 决策选型:业务正确性优先选唯一索引;极致写入性能且应用层已防重选普通索引。
怎么验证是否生效
使用以下命令检查表结构及索引类型,确认约束是否符合预期:
SHOW CREATE TABLE table_name;
观察输出中的 KEY 部分,确认是 UNIQUE KEY 还是 KEY,并检查列定义是否包含 NOT NULL。
通过慢查询日志或性能监控工具,观察写入场景下的磁盘 I/O 等待时间,验证 Change Buffer 是否生效。
常见坑
1. 唯一索引的 NULL 陷阱:MySQL 中唯一索引允许任意多个 NULL 值,因为 NULL 不等于 NULL,若业务要求唯一且非空,必须同时声明 NOT NULL。
2. 应用层防重不可靠:仅在代码层做“先查后插”无法保证并发下的唯一性,数据库层唯一索引是最后一道防线。
3. 盲目追求写入性能:放弃唯一索引换取 Change Buffer 性能提升,可能导致脏数据产生,修复成本远高于性能收益。
常见问题
普通索引和唯一索引查询速度差多少?
查询性能差异几乎可以忽略,两者都走 B+ 树查找,普通索引仅在找到记录后多一次内存内的判断操作。
唯一索引会影响写入性能吗?
会,唯一索引无法使用 Change Buffer,写入时若数据页不在内存,必须触发磁盘随机读进行唯一性校验。
唯一索引能存多个 NULL 吗?
可以,MySQL 规定唯一索引中 NULL 值不参与唯一性比较,因此允许存在多个 NULL 记录。
参考来源
- MySQL:普通索引和唯一索引对比-CSDN 博客
- mysql 普通索引和唯一索引怎么选择_mysql 索引类型对比
- MySQL 中普通索引和唯一索引该如何选择?
- MySQL 的普通索引和唯一索引到底什么区别?
- MySQL 实战之普通索引和唯一索引,应该怎么选择?