主键、外键、唯一约束是MySQL表结构设计的底线规则;主键强制唯一非空且仅一个,构成聚簇索引;外键需InnoDB引擎+显式启用才生效;唯一约束允许多NULL,可多个并自动建索引。

主键、外键、唯一约束不是“选配”,而是 MySQL 表结构设计的底线规则;漏掉或误用,轻则数据重复难查,重则 JOIN 结果错乱、业务逻辑崩塌。
主键(PRIMARY KEY)必须且只能有一个
主键是表中每一行的唯一身份证,MySQL 强制要求:每张表最多一个主键,且值不能为 NULL、不能重复。InnoDB 引擎下,主键还会自动成为聚簇索引,直接影响查询性能和磁盘存储布局。
实操建议:
- 优先用无业务含义的自增整数(
INT UNSIGNED AUTO_INCREMENT),避免用手机号、身份证号等可能变更或含隐私的数据做主键 - 联合主键(如
PRIMARY KEY (order_id, item_seq))可行,但会增加二级索引体积,JOIN 和 WHERE 条件必须包含全部列才高效 - 一旦设为主键,
ALTER TABLE ... DROP PRIMARY KEY会同时删掉聚簇索引,InnoDB 会重建整张表——大表慎操作
外键(FOREIGN KEY)不是 MySQL 默认开启的功能
外键用于强制两张表之间的引用完整性,比如 orders.user_id 必须存在于 users.id 中。但它在 MySQL 中默认不生效:只有引擎为 InnoDB 时才支持,且需显式定义,而且服务端配置 FOREIGN_KEY_CHECKS=1 才真正校验。
常见错误现象:
- 建表时加了
FOREIGN KEY但没报错,插入脏数据也不拦截 → 检查SHOW CREATE TABLE orders看是否真生成了外键,再查SELECT @@FOREIGN_KEY_CHECKS - 用
mysqldump导出再导入后外键失效 → dump 默认带SET FOREIGN_KEY_CHECKS=0,导入完要手动开回,或加--skip-foreign-key-checks参数控制 - 级联更新(
ON UPDATE CASCADE)看似方便,但可能意外改掉大量关联记录,生产环境建议禁用,靠应用层显式处理
唯一约束(UNIQUE)和主键的区别不止是“能不能 NULL”
UNIQUE 约束允许多个 NULL 值(注意:不是“一个 NULL”,是任意多个),而主键不允许任何 NULL。更关键的是,一张表可以有多个 UNIQUE 约束,它们各自生成独立的唯一索引,可用于加速去重查询或作为二级查找入口。
使用场景与陷阱:
- 邮箱字段加
UNIQUE是常规操作,但要注意大小写:MySQL 默认不区分大小写(utf8mb4_0900_as_cs除外),user@EXAMPLE.COM和user@example.com可能被当成重复 -
UNIQUE KEY (a, b)是联合唯一,但(1, NULL)和(1, NULL)不算冲突(因为 NULL 不参与比较),这和主键行为完全不同 - 删除唯一索引要用
DROP INDEX index_name ON table_name,不能用DROP UNIQUE—— MySQL 没这个语法
真正容易被忽略的点:主键和唯一约束都会自动创建 B+ 树索引,但外键列如果不单独建索引,DELETE FROM parent 会触发全表扫描子表来检查依赖——哪怕只是删一条父记录,也可能锁住整个子表几秒。别只盯着 DDL 语句,记得给外键列补上索引。










