Mysql的索引和主键的区别
索引是一种文件,它里面包含着对数据表里所有记录的引用指针。
# 1. 核心约束规则
1、 主键 PRIMARY KEY
- 一张表只能有 1 个主键;
- 字段不允许为 NULL;
- 自动自带唯一约束,值不能重复;
- InnoDB 中主键是聚簇索引,整行数据依附主键存储。
2、 唯一索引 UNIQUE INDEX
- 一张表可以创建多个唯一索引;
- 索引字段允许 NULL(多个 NULL 互不冲突,NULL != NULL);
- 仅保证非 NULL 值唯一。
# 2. 底层索引差异(InnoDB)
1、PRIMARY KEY
- 聚簇索引,叶子存完整行数据;
- 不允许空值,不会存在多条 NULL。
2、UNIQUE INDEX
- 二级普通唯一索引,叶子只存主键;
- 支持多条 NULL 记录共存。
# 3. 额外特性
- 主键会自动作为表默认排序依据,查询主键极快;
- 主键可被外键引用;唯一索引不能直接当外键参照;
- 创建主键时,MySQL 自动创建索引;UNIQUE 手动创建唯一索引。
# 疑问
# Q1 表没指定主键,InnoDB 会自动生成隐藏主键吗?
会,规则分两步判断:
先找表里任意一个非空、唯一的字段,自动把它当成主键;
如果不存在满足条件的列,MySQL 自动生成隐藏列:
row_id6 字节 bigint 自增;
用户不可见、无法查询、无法操作;
所有二级索引叶子存储这个 row_id 代替主键,导致索引变大、查询性能变差;生产环境
强制手动设置主键,禁止依赖隐藏 row_id。
# Q2 能不能修改 / 更换主键?
万一刚开始没设置主键,后续能不能修改了? 答案是 可以,两种场景:新增主键、更换原有主键
#
-- 1. 新增主键(原本无主键)
ALTER TABLE user ADD PRIMARY KEY(id);
-- 2. 更换主键(先删旧主键,再加新的)
ALTER TABLE user DROP PRIMARY KEY, ADD PRIMARY KEY(new_id);
# Q3 修改主键会不会锁表?
分 MySQL 版本。
# 1. MySQL 5.6 / 5.7(无 Online DDL 完整支持)
执行 ALTER TABLE ... DROP/ADD PRIMARY KEY
- 会锁表(独占写锁),期间所有 DML(增删改)阻塞;
- 原理:InnoDB 要重建整张聚簇索引,数据全部重排复制。
# 2. MySQL 8.0(支持 Instant DDL)
- 新增主键:依然需要重建聚簇索引,锁表;
- 删除主键:同样重建聚簇索引,锁表;
Instant DDL 仅适用于加普通字段、删字段等轻操作,主键变更属于重排数据,不支持瞬时修改。
所以更换主键成本极高:
- 聚簇索引全表重建;
- 所有二级索引全部更新(二级索引叶子存主键,主键一变所有索引都要改);
- 大表会产生长时间主从延迟,线上业务尽量避免中途更换主键。
# 总结
PRIMARY KEY / UNIQUE INDEX / 普通 INDEX 完整对比表
| 对比维度 | PRIMARY KEY 主键 | UNIQUE INDEX 唯一索引 | INDEX 普通索引 |
|---|---|---|---|
| 单表数量 | 仅能 1 个 | 允许多个 | 允许多个 |
| NULL 约束 | 字段不允许 NULL | 字段可存 NULL,多条 NULL 不冲突 | 字段允许任意 NULL,无唯一性限制 |
| 重复值 | 完全不允许重复 | 非 NULL 值不能重复 | 允许大量重复值 |
| InnoDB 索引类型 | 聚簇索引,叶子存整行数据 | 二级唯一索引,叶子存主键 | 二级普通索引,叶子存主键 |
| 能否做外键参照 | 支持 | 不支持 | 不支持 |
| 作用 | 唯一标识一行、表数据存储依据 | 保证业务字段唯一(手机号 / 身份证) | 加速等值 / 范围查询,无唯一性校验 |
| 复合字段 | 支持复合主键 | 支持复合唯一索引 | 支持联合普通索引 |
| 额外开销 | 无额外索引文件,表依赖它存储 | 独立索引,占用磁盘 | 独立索引,占用磁盘 |
| 重复插入报错 | 主键冲突报错 | 唯一键冲突报错 | 无报错,正常插入 |
上次更新: 2026-06-28 03:58:08