MySQL 主键详解:作用、使用方法与最佳实践(2025–2026 实用版)
主键(Primary Key)是 MySQL 中最核心、最基础的约束之一,理解它能帮助你设计出高效、可维护的表结构。
一、主键到底是什么?核心作用
主键有三个最本质的作用:
唯一性(Uniqueness)
表中每一行数据的主键值必须唯一,不能重复,也不能为 NULL。标识性(Identification)
主键是唯一能确定一行记录的字段(或字段组合),相当于每条数据的“身份证号”。聚集索引(Clustered Index)
在 InnoDB 引擎(MySQL 默认引擎)中,主键就是聚集索引的依据,表数据按照主键顺序物理存储。
一句话总结:
主键 = 唯一不为空 + 决定了数据的物理存储顺序 + 是查找最快的路径
二、主键的几种常见类型对比
| 类型 | 定义方式示例 | 是否允许 NULL | 是否自增 | 存储空间 | 适用场景 | 推荐程度(2025–2026) |
|---|---|---|---|---|---|---|
| 自然主键(业务字段) | order_idVARCHAR(32) | 否 | 否 | 中–大 | 业务有天然唯一标识(如订单号、车牌号) | ★★☆(慎用) |
| 代理主键(自增ID) | idBIGINT AUTO_INCREMENT | 否 | 是 | 8字节 | 绝大多数业务表 | ★★★★★(强烈推荐) |
| UUID 主键 | idCHAR(36) 或 BINARY(16) | 否 | 否 | 36/16字节 | 需要全局唯一、分布式系统 | ★★★☆(特定场景) |
| 复合主键(多列) | PRIMARY KEY (user_id, role_id) | 否 | 否 | — | 多对多关系表、唯一约束场景 | ★★☆(视情况) |
当前主流结论(InnoDB):
- 95%+ 的业务表都应该使用自增 BIGINT 主键(
id BIGINT UNSIGNED AUTO_INCREMENT) - UUID 适合分布式系统,但有性能代价
- 自然主键在大多数场景下不推荐作为主键(虽然可以作为唯一索引)
三、创建主键的几种写法
-- 方式1:建表时直接定义(最常见)CREATETABLEusers(idBIGINTUNSIGNEDAUTO_INCREMENTCOMMENT'主键ID',usernameVARCHAR(50)NOTNULL,created_atDATETIMENOTNULLDEFAULTCURRENT_TIMESTAMP,PRIMARYKEY(id))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;-- 方式2:列级约束CREATETABLEorders(order_idBIGINTUNSIGNEDAUTO_INCREMENTPRIMARYKEY,user_idBIGINTUNSIGNEDNOTNULL,amountDECIMAL(10,2)NOTNULL);-- 方式3:复合主键CREATETABLEuser_roles(user_idBIGINTUNSIGNEDNOTNULL,role_idINTUNSIGNEDNOTNULL,PRIMARYKEY(user_id,role_id));-- 方式4:已有表添加主键(慎用)ALTERTABLEusersADDPRIMARYKEY(id);四、自增主键最常见的写法(推荐模板)
CREATETABLEexample(idBIGINTUNSIGNEDAUTO_INCREMENTCOMMENT'主键ID',-- 业务字段user_idBIGINTUNSIGNEDNOTNULLDEFAULT0,titleVARCHAR(200)NOTNULLDEFAULT'',statusTINYINTUNSIGNEDNOTNULLDEFAULT0COMMENT'0=草稿,1=发布,2=删除',created_atDATETIMENOTNULLDEFAULTCURRENT_TIMESTAMP,updated_atDATETIMENOTNULLDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMP,-- 索引INDEXidx_user_id(user_id),PRIMARYKEY(id))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4COLLATE=utf8mb4_unicode_ciCOMMENT='示例表';推荐字段顺序:
主键 → 业务常用查询字段 → 状态/时间字段 → 其他
五、主键相关的常见问题与注意事项
为什么不推荐 UUID 做主键?
- 插入性能差(随机性导致页分裂)
- 索引占用空间大(36字节 vs 8字节)
- 排序效率低
- 联合索引时前缀不友好
自增 ID 会不会用完?
- BIGINT UNSIGNED:0 ~ 18446744073709551615(约 1840 亿亿)
- 即使每天插入 1 亿条,也要用 5000+ 年
主键能改吗?
能,但代价极大(会重建整个表和所有二级索引)
生产环境几乎不要改主键。删除主键后还能恢复吗?
不建议直接删除主键。
如果误删,建议加回同结构主键(但自增会从 1 开始,除非用AUTO_INCREMENT = n指定)。外键一定需要主键吗?
外键引用的一定是被引用表的唯一键(可以是主键,也可以是唯一索引)。
六、实际场景选择建议
| 场景 | 推荐主键类型 | 理由简述 |
|---|---|---|
| 用户表、订单表、文章表 | BIGINT 自增 | 顺序插入、高效、简单 |
| 分布式系统全局唯一ID | UUID v7 / Snowflake / ULID | 避免 ID 冲突 |
| 多对多中间表 | 复合主键(两列) | 天然唯一 + 节省空间 |
| 需要业务含义的编码 | 业务字段 + 唯一索引 | 主键仍用自增,业务码做唯一约束 |
| 日志表、监控表 | BIGINT 自增 或 不设主键 | 追求极致写入性能,可不设主键 |
七、总结口诀
- 默认用:
BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY - 不建议用:VARCHAR、UUID 做主键(除非有特殊需求)
- 必须保证:主键唯一、不为空
- InnoDB 特性:主键 = 聚集索引,决定了数据物理顺序
- 生产建议:主键字段放在表最前面,命名为
id
你现在是在设计新表,还是在优化老表?
或者有具体的场景(比如分布式系统、日志表、多租户等),我可以给你更针对性的表结构建议。