主键、外键与约束
主键、外键和约束共同定义表内身份、跨表引用与持久化数据的合法状态。
#synthesis
#growing
#backend
#database
#sql
[!info] related notes
主键、外键与约束
范围
这篇不重复背诵三个术语,而是解释它们如何一起回答关系数据库最基本的三个问题:
这一行是谁?
它引用谁?
什么状态允许被保存?
三层职责
| 概念 | 核心问题 | 典型 SQL |
|---|---|---|
| 主键 | 这一行是谁 | PRIMARY KEY |
| 外键 | 这一行引用谁 | FOREIGN KEY ... REFERENCES ... |
| 约束 | 什么数据状态合法 | NOT NULL、UNIQUE、CHECK 等 |
主键和外键本身也属于约束体系,只是它们分别承担“身份”和“引用完整性”这两个特殊角色。
从业务关系到数据库约束
假设:
User 1 ─── N Assessment
常见实现:
CREATE TABLE assessments (
id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL REFERENCES users(id),
score INTEGER CHECK (score BETWEEN 0 AND 100)
);
这里同时表达:
id
→ Assessment 自己是谁
user_id
→ 它属于哪个 User
NOT NULL / CHECK
→ 哪些 Assessment 状态合法
Application 与 Database 的分工
应用层可以做同样的预检查,但数据库承担的是最终持久化边界:
Application
→ 输入校验、领域语义、友好错误、Authorization
Database
→ UNIQUE / FK / CHECK 等可强制的数据不变量
例如“先查询邮箱是否存在再创建”仍可能遇到并发竞争;最终的唯一性应由数据库 UNIQUE 守住。
与 JOIN 的边界
FOREIGN KEY 和 JOIN 经常一起出现,但不是同一个东西:
FK
→ 写入时保证关系可信
JOIN
→ 读取时沿关系组合数据
没有 FK 也能 JOIN;有 FK 也不意味着必须 JOIN。
建模顺序
一种实用顺序是:
- 明确实体和关系基数;
- 为实体选择稳定主键;
- 在 1:N 的 N 侧建立外键;
- N:M 时引入连接表;
- 把必填、唯一、范围等持久化不变量表达成约束;
- 再根据查询与性能模式补索引。
这比先从 ORM API 反推数据库结构更稳定。