Files
test-repo/docs/zh-cn/appendix/5-data/data-models.md
T

115 lines
6.7 KiB
Markdown
Raw Normal View History

# 数据模型:设计的强健骨架
::: tip 🎯 核心问题
**如果房子没有蓝图,那盖到一半该怎么走线和装门呢?**
当我们构建一个涉及百万用户和千万订单的电商应用时:用户的地址、订单号、支付状态该如果高效摆放?如果今天加了个折扣功能,明天又要发优惠券该怎么扩展?本章带你重回设计的“地基”,理清这些表该怎么长出最强健的骨架:**数据模型设计 (Data Modeling)**。
:::
---
## 0. 先问一个问题:你有没有经历过这些噩梦?
在一个软件项目最初狂欢般的冲刺期,很多人会用最粗暴的方式写下他们的结构。
```text
users 表:
| id | name | address | order_1 | order_1_amount | order_2 | order_2_amount | ... |
```
这看起来非常省事对吧?直接把这辈子有关张三的一切统统塞到他的这行里!
但过了三个月,老板满怀希冀地找你说:
“咱们需要给买了三次以上的大客户发红包。”
这下你直接傻眼了:这表不仅已经蔓延出一百多个 `order_n` 的臃肿字段,而且每一次为了查询订单,系统都要横跨几千条记录的一大长串烂摊子进行全盘扫除。
这,就是没有良好**数据模型(Data Model)**直接硬造的典型**灾难和噩梦**。
---
## 1. 实体与关系:万物皆有连接
2026-02-24 00:18:09 +08:00
我们要建立一个清晰的秩序世界,在这个世界里,首先得有基本的主角和配角:我们称他们为**“实体(Entities)”**。
它们就是现实世界被抽象到计算机中的那些主要对象。比如:用户、订单、商品。
2026-02-24 00:18:09 +08:00
紧接着最重要的部分来了——如何把这些零散的东西连接起来?
你总不能让这些主角像孤岛一样吧?张三买了一部手机,这中间发生了一个奇妙的桥梁,这就是**"关系(Relationships)"**。
2026-02-24 00:18:09 +08:00
这套把实体及其关系用精美的符号画出来的世界地图,被称为 **ER 图(Entity-Relationship Diagram**
2026-02-24 00:18:09 +08:00
<DataModelsDemo tab="er" />
2026-02-24 00:18:09 +08:00
### 1.1 世界上只有三种最基本的连接
2026-02-24 00:18:09 +08:00
当我们把镜头死死盯在任意两个实体之间时,你会发现所有的连接无外乎可以提纯为下面三种形式:
2026-02-24 00:18:09 +08:00
<DataModelsDemo tab="relationships" />
2026-02-24 00:18:09 +08:00
- **一对一 (One-to-One, 1:1)**
这是非常罕见和亲密的。比如一个中国人唯一对应一张身份证。或者在系统里,一个账号唯一的绝密隐私档案。
- **一对多 (One-to-Many, 1:N)**
这是我们构建系统打交道最多的一种形态。一个作者能写出几百篇文章,但这几百篇文章的创作者只能是这一个特定的作者。此时在表中增加的外键(FK)就像个锚点,把多的一方牢牢锚向了一的一方。
- **多对多 (Many-to-Many, M:N)**
这就极其复杂了。一个学生能选五门不同的课,一门课可能坐着五十个不同的学生。想要理顺这个乱作一团的毛线团,我们就得硬生生塞进一张中间表(中间人):比如“选课记录表”。
2026-02-24 00:18:09 +08:00
---
## 2. 范式理论:从混乱到干净利落的切分
如果关系确定了,那我们就在表里面无限塞字段吧?
绝不!在长达数十年的计算机演进中,顶级的数据库专家们制定了一个近乎严苛的出厂规范,用来防止表中出现垃圾一般的冗余或者逻辑漏洞,这套铁律就叫——**数据库范式 (Normalization)**。
<DataModelsDemo tab="normalization" />
- **第一范式 (1NF) :不要大杂烩!**
你不能在一个字段里塞进去“张三,北京,25岁”。每一列都必须劈到底、拆到最细的原子级别。
- **第二范式 (2NF) :消除附庸者的脚踏两只船**
当主键是两个字段联合组成时,绝对不允许有的杂兵字段只去巴结其中一半的主键而跟另外一半毫无关联。每一列都得完全依附于整体的联合主导。
- **第三范式 (3NF) :不要越级传递依赖**
这是至高原则。既然你是依附于学号的个人信息,那你就好好当附庸,不能再出现“学号决定学院编号,而学院编号又能决定学院电话”的荒谬级联。
严苛遵循到 3NF,你的数据将呈现出令人如痴如醉的干净:**没有任何一句废话重复两遍,每次修改信息绝不会拖泥带水!**
---
## 3. 反范式化:在刀尖上跳舞的设计哲学
2026-02-24 00:18:09 +08:00
等等,既然范式这么严谨完美。难道所有大厂、千万级并发的电商真的就在 3NF 的象牙塔里搭建一切吗?
2026-02-24 00:18:09 +08:00
**残酷的性能现实很快打脸了:绝对不是。**
<DataModelsDemo tab="denormalization" />
假设你想展现一个带商品名字和买家名字的最终订单页面。按照 3NF:
“天呐,我需要在一毫秒内把 订单表、用户表、商品表、库存表 进行足足三次的巨大内部 JOIN (狂暴连接计算) 才能凑齐这十几个字段去页面呈现!”
由于巨大的服务器开销,高并发下数据库瞬间融化。
所以,在极端讲究速度的现代互联网中,我们往往会采取一种逆天之举:**故意破坏范式(Denormalization),空间换时间**。
通过在订单表里刻意“冗余”了一份本来只该出现在用户表里的买家姓名,虽然占据了一点点磁盘,但这换来了查询时雷霆般惊人的单表吞吐力。
这就是架构师在系统设计时那最精妙的取舍。
---
## 4. 全景实战:拆解电商系统
理解了以上所有原理,不妨让我们戴上前人的结晶。看一看在现代的电商和社交系统背后,是如何用这些一块块小积木,搭建起了扛得住双十一每秒几十万张海量洪峰订单的巨大钢铁森林。
2026-02-24 00:18:09 +08:00
<DataModelsDemo tab="ecommerce" />
### 4.1 直面反模式设计
2026-02-24 00:18:09 +08:00
当然,在构建这些巨无霸的过程中。无数的新手总会栽进那些前辈踩烂了的巨幅陷阱中。当你在表里面用逗号狂拼接字段(所谓的 JSON 万金油),或者在一张巨表里面加到第 150 个字段时。
2026-02-24 00:18:09 +08:00
你必须警惕了,这是一个极度不详的征兆。
2026-02-24 00:18:09 +08:00
<DataModelsDemo tab="antipatterns" />
2026-02-24 00:18:09 +08:00
## 5. 总结:用数据模型构建千秋地基
2026-02-24 00:18:09 +08:00
万丈高楼平地起。我们在任何花里胡哨的前端页面、后端微服务设计之前。最朴素的那张在草稿纸上被反复涂改的实体关系图,往往决定了这个团队能不能挺过第三年的需求大爆炸。
- **用理清从属和多维关系(1:1, 1:N, M:N)的基座,框定业务的脉络。**
- **用严酷的三大范式的修剪,剃除无端的数据黑洞与混乱堆砌。**
- **用大巧不工的反范式策略平衡,抵御性能瓶颈这头怪兽。**
所以,在下次打开代码编辑器兴奋地敲击之前,先买一张大大的白板。跟你的伙伴讨论出你们心中最干净的那个模型。因为只有拥有了强健的数据骨架,这头怪兽才能放肆奔跑。