← [ BACK_TO_NOTES ]

数据库规范化

数据库规范化通过明确函数依赖、减少重复事实和拆分不合理结构,降低插入、更新与删除异常。

#concept #growing #backend #database

[!info] related notes

数据库规范化

一句话定义

规范化不是“把表拆得越多越好”,而是根据数据依赖关系让一个事实尽量只在合适的位置表达,从而减少冗余和更新异常。

为什么需要规范化

假设每篇 Article 都重复存作者名字:

article_id | user_id | user_name
1          | 10      | Sean
2          | 10      | Sean
3          | 10      | Sean

如果用户改名,需要同时更新很多行;漏掉一行就出现互相矛盾的事实。

更合理的结构通常是:

users
id | name
10 | Sean

articles
id | user_id
1  | 10
2  | 10
3  | 10

查询时再通过 JOIN 组合。规范化与 JOIN 因此是同一建模取舍的两面。

1NF:原子值与重复组

第一范式强调关系中的每个属性位置应表示该属性域中的一个值,不用“第 1 个电话、第 2 个电话、第 3 个电话”这类重复列来模拟集合:

phone_1
phone_2
phone_3

如果一个 User 可以有多个 Phone,更稳定的关系建模通常是:

User 1 ─── N Phone

这里的“原子”不是物理意义上的不可再切分。例如一个日期内部当然包含年/月/日;关键是对当前关系模型和查询语义而言,它被当作一个域值处理。

现代数据库支持 JSON、ARRAY 并不意味着“使用一次数组就违反 1NF”。是否应该拆表仍取决于该值是否需要独立身份、约束、引用、查询和生命周期;不要把范式口诀机械化。

2NF:消除对复合键一部分的依赖

2NF 主要在复合候选键场景中有意义:非主属性应该依赖整个候选键,而不是只依赖其中一部分。

例如 Enrollment 以 (student_id, course_id) 标识一条选课关系:

student_name

只依赖 student_id,不依赖整个 Enrollment,应放回 Student,而不是重复在每条 Enrollment 中。

3NF:减少传递依赖

如果:

employee_id → department_id
department_id → department_name

那么 department_name 本质上依赖 Department,不应因为 Employee 引用了 Department 就在每个 Employee 行里重复保存。

BCNF

BCNF 比 3NF 更严格,要求每个非平凡函数依赖的决定因素都是候选键。它用于处理某些 3NF 仍可能留下的异常结构;初学阶段先把“函数依赖”和 1NF/2NF/3NF 理清,再深入 BCNF 更合适。

三类异常

不合理冗余常带来:

Update anomaly
→ 同一事实必须改很多处

Insert anomaly
→ 想记录一个事实,却被迫同时提供另一个无关事实

Delete anomaly
→ 删除某条业务记录时意外丢掉唯一的一份其他事实

规范化的真正目标是降低这些异常,而不是追求表数量。

什么时候允许反规范化

为了读性能、报表、搜索或缓存,可以有意识地重复数据,但需要明确:

  • 哪个来源是 authoritative source;
  • 副本如何同步;
  • 允许多长的一致性延迟;
  • 如何修复漂移。

“为了性能重复存”是工程权衡;“不知道这是重复事实”则是建模问题。

当前掌握边界

当前已掌握规范化的直觉:减少重复事实、1:N/N:M 拆分、1NF 原子值和常见异常;2NF/3NF/BCNF 的严格函数依赖推导尚未经过专项练习,因此 mastery 暂保持 2。

创建于 2026/5/3 更新于 2026/9/14
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本