沉默是金,总会发光
大家好,我是沉默
我们在设计数据库时,常常被一句话刷屏:“一定要遵守三大范式!”
但现实中,许多优秀的系统反而“破坏”了范式。难道三大范式是“看起来很美”,实际却不管用?
今天这篇文章,就来帮你通透理解:
✅ 三大范式到底是什么?
✅ 哪些场景你可以放心“破坏范式”?
✅ 为什么说范式不是圣旨?
**-**01-
三大范式到底是什么?
数据库设计的三大范式,类比一下,就像整理房间的三步曲:
-
第一范式(1NF):东西不能堆一起,要“每件物品各就各位”
-
第二范式(2NF):同类物品要放一起,不要一个柜子塞两类东西
-
第三范式(3NF):信息不重复,一个标签贴在一个地方
数据库三大范式就是为了消除冗余、提高一致性、简化维护,它不是约束你,而是帮助你。
接下来我们一个一个拆解。
1. 第一范式(1NF):字段必须原子化,不可再分
举例:有这样一个学生表
| 学生ID
|
姓名
|
电话号码
| | --- | --- | --- | |
1
|
张三
|
123456789, 987654321
| |
2
|
李四
|
555555555
|
问题:电话有多个,逗号分隔,这就像你把袜子、内裤、T恤全塞进一个抽屉——乱!
正确做法:拆成两张表!
- 学生表
| 学生ID
|
姓名
| | --- | --- | |
1
|
张三
| |
2
|
李四
|
- 电话表
| 电话ID
|
学生ID
|
电话号码
| | --- | --- | --- | |
1
|
1
|
123456789
| |
2
|
1
|
987654321
| |
3
|
2
|
555555555
|
这样一来,每一列都是原子值,查询、更新、统计都更轻松。
2. 第二范式(2NF):字段必须完全依赖主键,不能只依赖“其中一半”
这是在 1NF 基础上的升级,主要应用在 复合主键 的表。
来看这个订单详情表
| 订单ID
|
商品ID
|
商品名称
|
数量
|
单价
| | --- | --- | --- | --- | --- | |
1001
|
A01
|
苹果
|
10
|
2.5
| |
1001
|
A02
|
橙子
|
5
|
3.0
| |
1002
|
A01
|
苹果
|
7
|
2.5
|
问题:商品名称和单价,其实只跟商品ID有关,和订单ID没关系。这就像你把商品简介贴在订单单据上——重复冗余。
正确拆法:
- 订单详情表
| 订单ID
|
商品ID
|
数量
| | --- | --- | --- | |
1001
|
A01
|
10
| |
1001
|
A02
|
5
| |
1002
|
A01
|
7
|
- 商品表
| 商品ID
|
商品名称
|
单价
| | --- | --- | --- | |
A01
|
苹果
|
2.5
| |
A02
|
橙子
|
3.0
|
从此,商品价格改了只需动一处,不怕多处更新错漏。
3. 第三范式(3NF):字段不能通过“其他字段”间接依赖主键
还是那句话——一个字段的值,必须直接依赖主键,而不是依赖另一个非主键字段。
举个例子
| 员工ID
|
员工姓名
|
部门ID
|
部门名称
| | --- | --- | --- | --- | |
E01
|
王五
|
D01
|
销售部
| |
E02
|
赵六
|
D02
|
技术部
| |
E03
|
孙七
|
D01
|
销售部
|
问题:部门名称其实依赖的是部门ID,而部门ID又依赖员工ID,形成了“传递依赖”。
正确分拆:
- 员工表
| 员工ID
|
员工姓名
|
部门ID
| | --- | --- | --- | |
E01
|
王五
|
D01
| |
E02
|
赵六
|
D02
| |
E03
|
孙七
|
D01
|
- 部门表
| 部门ID
|
部门名称
| | --- | --- | |
D01
|
销售部
| |
D02
|
技术部
|
一改部门名称,全体员工自动生效,省心!
**-**02-
哪些场景你可以放心“破坏范式”?
你可能会问:
三大范式这么香,为什么真实项目反而会反范式设计?
因为设计数据库不只是追求纯洁性,还要考虑性能、复杂度、成本与业务演进速度。
以下是“可以破坏范式”的 7 类典型场景:
1. 性能优化:冗余数据,减少 JOIN
订单表原本只保存用户ID,要查用户信息得联表。
优化后:
在订单表冗余用户名、地址,直接展示,查询更快。
2. 简化开发:少联表,逻辑简单
CMS 系统中,文章表 + 分类表经常联表取分类名。
优化后:
直接在文章表冗余“分类名称”,接口简单、开发轻松。
3. 报表系统:星型模型天然反范式
BI 报表中,事实表直接存储产品名、类别名、日期等维度数据。
目的: 快速生成图表,避免复杂 SQL。
4. 实时业务需求:保持写时一致,提高查询效率
例如账户余额、好友数量,不实时计算,而是写入时维护一个冗余字段。
5. 快速迭代:初创项目更看重上线速度
刚起步的项目不需要复杂拆表,字段全堆一个表中,迭代快。
后期需求稳定,再逐步范式化。
6. 降低协作成本:结构直观,新人易懂
冗余字段降低了逻辑复杂度,前后端都更容易读懂和维护。
7. 读多写少场景:读性能优先,牺牲部分写入一致性
如用户主页展示的统计数据、推荐内容等。
**-**03-
为什么说范式不是圣旨?
设计数据库,不是靠死记范式,而是基于业务权衡
推荐策略:
| 场景
|
是否严格范式
|
原因
| | --- | --- | --- | |
核心交易系统
|
✅ 是
|
强一致性、高并发
| |
报表分析系统
|
❌ 否
|
查询性能优先
| |
初创快速迭代
|
❌ 否
|
上线速度 > 完美设计
| |
成熟大型系统
|
⚖️ 权衡
|
范式 + 局部冗余混合
|
而是否“破坏”范式?请始终牢记这句话:
设计是为了更好地服务业务,不是为了奉命行事。
**-**04-
总结
-
1NF:每列只存一个值,别搞“电话1,电话2”
-
2NF:字段不能只依赖主键的一部分
-
3NF:字段不能间接依赖主键,要直接挂钩
一句话总结:
范式是一种“默认的正确”,但不是唯一正确。设计数据库,是在性能、扩展性与开发效率之间找到最优解。
**-**05-
粉丝福利
点点关注,送你 SQL Server 性能调优实战,如果你正在优化 SQL,又或者刚准备调优性能。可以仔细阅读一下,或许对你有所帮助!