数据库三范式(Three Normal Forms, 3NF) 是关系型数据库设计中用于减少数据冗余、避免更新异常、保证数据一致性的一套规范化理论。它由 E.F. Codd 提出,是 OLTP(联机事务处理)系统数据库设计的核心原则。
三范式是逐级递进的:满足第二范式必须先满足第一范式,满足第三范式必须先满足第二范式。
一、第一范式(1NF):字段不可再分
定义:表中的每一列都是原子性的(Atomic),即不可再拆分为更小的数据项。
✅ 满足 1NF 的要求:
- 每个字段只包含单一值,不能是集合、数组或复合结构。
- 每一行在表中是唯一的(通常通过主键保证)。
❌ 反例(违反 1NF):
-- 错误:爱好字段包含多个值
用户表:
| user_id | name | hobbies |
|---------|-------|------------------|
| 1 | 张三 | 游泳, 篮球, 阅读 |
✅ 正确做法(拆分为多行或多表):
用户表:
| user_id | name |
|---------|-------|
| 1 | 张三 |
用户爱好表:
| user_id | hobby |
|---------|-------|
| 1 | 游泳 |
| 1 | 篮球 |
| 1 | 阅读 |
💡 核心思想:列不可再分。
二、第二范式(2NF):消除部分依赖
定义:在满足 1NF 的基础上,非主键字段必须完全依赖于整个主键,而不能只依赖于主键的一部分。
⚠️ 前提:表的主键是复合主键(由多个字段组成)。如果主键是单字段,则自动满足 2NF。
❌ 反例(违反 2NF):
订单明细表(主键 = (order_id, product_id)):
| order_id | product_id | product_name | quantity | order_date |
|----------|------------|--------------|----------|------------|
| 1001 | P100 | 手机 | 2 | 2024-11-01 |
| 1001 | P101 | 耳机 | 1 | 2024-11-01 |
问题分析:
product_name只依赖于product_id(与order_id无关)→ 部分依赖order_date只依赖于order_id(与product_id无关)→ 部分依赖
后果:
- 数据冗余:同一订单的
order_date重复多次。 - 更新异常:修改订单日期需更新多行。
- 插入异常:无法在没有商品的情况下记录订单。
✅ 正确做法(拆表):
订单表:
| order_id | order_date |
|----------|------------|
| 1001 | 2024-11-01 |
商品表:
| product_id | product_name |
|------------|--------------|
| P100 | 手机 |
| P101 | 耳机 |
订单明细表:
| order_id | product_id | quantity |
|----------|------------|----------|
| 1001 | P100 | 2 |
| 1001 | P101 | 1 |
💡 核心思想:非主键字段不能只依赖复合主键的一部分。
三、第三范式(3NF):消除传递依赖
定义:在满足 2NF 的基础上,非主键字段之间不能有依赖关系(即不能存在“传递依赖”)。
传递依赖:A → B → C,则 A → C 是传递依赖(C 传递依赖于 A)。
❌ 反例(违反 3NF):
员工表:
| emp_id | name | dept_id | dept_name | dept_manager |
|--------|-------|---------|--------------|--------------|
| E001 | 张三 | D10 | 研发部 | 李四 |
问题分析:
dept_id → dept_name,dept_id → dept_manageremp_id → dept_id,所以emp_id → dept_name是传递依赖- 非主键字段
dept_name依赖于另一个非主键字段dept_id
后果:
- 数据冗余:每个研发部员工都重复存储“研发部”和“李四”。
- 更新异常:更换部门经理需更新所有该部门员工记录。
✅ 正确做法(拆表):
员工表:
| emp_id | name | dept_id |
|--------|-------|---------|
| E001 | 张三 | D10 |
部门表:
| dept_id | dept_name | dept_manager |
|---------|--------------|--------------|
| D10 | 研发部 | 李四 |
💡 核心思想:非主键字段必须直接依赖于主键,不能依赖其他非主键字段。
四、三范式总结对比
| 范式 | 核心要求 | 解决的问题 | 关键词 |
|---|---|---|---|
| 1NF | 字段原子性 | 字段包含多个值 | 不可再分 |
| 2NF | 消除部分依赖 | 非主键依赖主键的一部分 | 完全依赖(针对复合主键) |
| 3NF | 消除传递依赖 | 非主键依赖另一个非主键 | 直接依赖 |
五、三范式的适用场景与局限
✅ 适用场景:
- OLTP 系统(如电商订单、银行交易):高并发写入,要求数据一致性和完整性。
- 需要强事务支持的业务系统。
⚠️ 局限性(在数仓/OLAP中不适用):
- 查询性能差:分析时需大量 JOIN 多张表。
- 模型复杂:业务人员难以理解。
- 写入优化 ≠ 读取优化:数仓以“读”为主,更关注查询效率。
📌 因此,数据仓库通常采用“维度建模”(星型模型),故意违反 3NF,通过冗余换取查询性能。
✅ 终极口诀:
1NF:列不可分;
2NF:非主键全靠主键;
3NF:非主键不靠非主键。
掌握三范式,是设计健壮业务数据库的基础;而知道何时“打破”三范式,则是构建高效数据仓库的关键。

1051

被折叠的 条评论
为什么被折叠?



