🚀 SQL 外键
引言
在关系型数据库设计中,外键(Foreign Key)是建立表间关联的核心机制。
一、外键的本质:不是列名,而是约束
核心定义:
外键是表中用于关联另一张表的列,但关联通过外键约束(Foreign Key Constraint)实现,而非仅靠列名。
示例:
在学生表students中添加class_id列关联班级表classes的主键id:
-- 添加外键约束
ALTER TABLE students
ADD CONSTRAINT fk_class_id -- 约束名称可自定义
FOREIGN KEY (class_id) -- 声明外键列
REFERENCES classes (id); -- 关联目标表的主键
关键点:
- 约束可防止无效数据插入(如
class_id=99但classes表无此班级)。 - 实际开发中,因性能考量(约束会增加数据库开销),常仅通过应用逻辑保证关联正确性,此时
class_id只是普通列,但逻辑上仍是外键。
二、表间关系的三种形态
1. 一对多(最常用)
场景:一个班级对应多个学生(classes → students)。
实现:
在「多」的一方(students表)添加外键列class_id,指向「一」方(classes表)的主键id。
数据示例:
-- classes表(一)
id | name
1 | 一班
2 | 二班
-- students表(多)
id | class_id | name
1 | 1 | 小明
2 | 1 | 小红
3 | 2 | 小白
2. 多对多(需中间表)
场景:一个老师可教多个班级,一个班级可有多个老师(teachers ↔ classes)。
实现:
创建中间表teacher_class,包含两个外键列teacher_id和class_id,分别关联两张表的主键。
数据示例:
-- teachers表
id | name
1 | 张老师
2 | 王老师
-- classes表
id | name
1 | 一班
2 | 二班
-- 中间表 teacher_class
id | teacher_id | class_id
1 | 1 | 1
2 | 1 | 2
3 | 2 | 1
核心逻辑:通过中间表,将多对多拆解为两个一对多(teachers→teacher_class,classes→teacher_class)。
3. 一对一(可拆可合)
场景:
- 学生联系方式(
students↔contacts):部分学生无手机号,可将联系方式单独存表。 - 大表拆分(如用户基本信息
user_info↔ 详细信息user_profiles):提升查询性能。
实现:
在关联表中添加外键列(如contacts表的student_id),指向主表主键,且保证唯一。
数据示例:
-- students表
id | name
1 | 小明
-- contacts表(一对一)
id | student_id | mobile
1 | 1 | 135xxxx6300
注意:一对一关系可直接合并为一张表,拆分需根据业务需求(如避免空值、优化查询)决定。
三、外键约束的增删操作
1. 删除外键约束
ALTER TABLE students
DROP FOREIGN KEY fk_class_id; -- 删除约束,但保留class_id列
2. 删除外键列(非约束)
ALTER TABLE students
DROP COLUMN class_id; -- 彻底删除列
四、实战避坑指南
💡 为什么互联网应用常不启用外键约束?
- 性能原因:约束会增加插入 / 更新数据时的校验开销,影响高并发场景性能。
- 替代方案:通过应用层逻辑(如接口参数校验、事务控制)保证数据一致性。
⚠️ 多对多中间表的设计要点
- 中间表至少包含两个外键列,可根据需求添加额外字段(如老师授课时间
start_time)。 - 中间表的两个外键通常组合为联合主键,或单独设置自增主键。
📌 一对一拆分表的适用场景
- 字段使用率差异大:高频字段放主表,低频字段放从表。
- 数据完整性要求低:允许从表记录缺失(如可选填写的用户资料)。
五、总结
- 外键的核心作用:定义表间关系,实现数据关联。
- 三种关系的本质:一对多是基础,多对多靠中间表,一对一可灵活拆分。
- 工程权衡:约束 vs 性能,需根据业务场景选择合适的实现方式。
一句话口诀:
一对多,外键直接加;多对多,中间表来搭;一对一,拆合看需求,约束性能要权衡!