很久很久以前,当恐龙还很大的时候……呃,其实是在1970年,有个人叫Edgar Codd,他觉得数据里的混乱已经不是“有创意的乱”,而是像个黑洞一样吞噬时间和资源。Edgar想了很久,终于想出了一个办法来整理一切,顺便也为整个数据世界打下了基础——在这里,数据被整齐地放进表格里,就像理想图书馆里书本排得整整齐齐。行、列、顺序——没有“差不多就行”或者“你懂就好”这种说法。
关系型模型的核心思想是把数据表示成表格,每个表由行和列组成。很直观:行就是记录,列就是记录的属性或特征。这样做让数据处理和操作都变得简单多了。
想象一下你在网店下单。为了让订单顺利处理和送达,系统得考虑很多细节:你是谁(买家)、你选了哪家快递、送到哪里、怎么追踪包裹状态。
如果所有这些信息都放在一个巨大的表里,肯定乱套:数据会重复,更新很麻烦,查找也更难。关系型方法就是帮你把信息分开存到不同的表里,这些表还能互相交流数据。
下面这个图就是快递追踪流程的数据组织示例:
- 买家 - 这里存着每个客户的信息——有唯一的买家编号。
- 快递服务 - 这个表列出了所有可以送货的快递公司,每家有自己的服务编号。
- 订单配送 - 这是核心的关联表。每一行就是一次具体的配送。它有自己的配送编号,还会关联买家、快递服务、具体订单、日期和当前状态。
箭头表示订单配送表里的记录是怎么和买家、快递服务表里的记录关联的。
订单配送表的一个例子:
| 配送编号 | 买家编号 | 服务编号 | 订单编号 | 创建日期 | 配送状态 |
|---|---|---|---|---|---|
| 121 | 101 | 1 | 1569 | 2025-03-23 | 已送达 |
| 122 | 234 | 3 | 1570 | 2025-03-24 | 已送达 |
| 123 | 1011 | 2 | 1571 | 2025-03-25 | 进行中 |
| 124 | 1011 | 2 | 1572 | 2025-03-25 | 等待中 |
这种做法的好处:
- 客户或快递服务的信息只存一份,避免每条配送记录都重复写一遍。
- 通过唯一编号(也叫键)建立关联,能保证不会出现比如“没有客户的配送”或“用不存在的快递服务”的情况。
- 可以很方便地把不同表的数据组合起来,做复杂报表或查找。
- 数据只改一次,所有相关操作都能马上用到最新的(比如快递服务的电话)。
关系型数据库的结构
关系型数据库的核心就是表。每个表都有:
- 名字(Table Name),方便我们识别——比如customers。
- 一组列(Columns/Attributes),定义对象的属性。
- 给那些做唯一编号(主键)的列命名时,通常用
名字_id这种格式。后缀_id就是“identifier”的意思。比如:买家编号就变成customer_id。 - 比如customers表:可以有
customer_id、first_name、email等等。
- 给那些做唯一编号(主键)的列命名时,通常用
- 行里的数据(Rows/Records)——customers表的一行,就是某个具体买家的全部信息(101,Alex Song等等)。
来看个表的例子——customers:
| customer_id | full_name | phone_number | delivery_address | registration_date | |
|---|---|---|---|---|---|
| 101 | Alex Song | alex.song@example.com | 555-0101 | 123 Main St, Anytown | 2023-01-15 |
| 234 | Maria Garcia | maria.g@example.org | 555-0102 | 456 Oak Ave, Otherville | 2022-11-30 |
| 1011 | David Lee | david.lee@example.net | 555-0103 | 789 Pine Ln, Sometown | 2023-03-01 |
表的键
为了唯一标识表里的每一行,会用到主键(Primary Key, PK)。这是某一列(或几列),它的值对每一行都是唯一的,不能是空的。你可以把它当成每条记录的身份证号,比如我们customers表里的customer_id:能唯一标识每个买家。
主键就像护照,更准确说像护照号:每个对象都唯一。这样就不会有重名行搞混了。
要让表之间建立联系,就要用到外键(Foreign Key, FK)。这是某个表里的列,它指向另一个表的主键。外键就是表之间的“桥梁”。外键的名字通常和它指向的主键一样。比如在deliveries表里,customer_id就是外键,存的是customers表customer_id的值,这样配送就和买家关联起来了。
这就是我们熟悉的结构,不过现在更贴近实际了。
- customers表存客户信息;它的主键是
customer_id。 - delivery_services表存快递服务信息;它的主键是
service_id。 - orders表(为了完整性,这里也画出来了,因为
order_id被配送表引用)用来存订单信息,主键是order_id。 - deliveries表是配送操作的核心。它有:
- 自己的主键:
delivery_id。 - 三个外键来建立关联:
customer_id(FK):把配送和customers表里的买家关联起来。service_id(FK):把配送和delivery_services表里的快递服务关联起来。order_id(FK):把配送和orders表里的订单关联起来。
created_date字段表示配送记录的创建时间。
- 自己的主键:
这样用主键和外键就能保证数据完整性。比如你不能插入一个customer_id或order_id在相关表里不存在的配送记录,而且还能灵活查出所有相关信息。
关系型模型的优点
关系型模型有很多很牛的优点,让它在各种数据库方案里脱颖而出:
- 结构简单。表格、列、行一目了然。
- 数据操作灵活。想加新数据、改数据都很方便,不会破坏整体一致性。
- 支持复杂查询。用SQL能从很多表里查数据、组合、筛选,几乎能满足你所有需求。比如查所有选了某门课的学生——so easy!
- 通过键保证数据完整性。主键和外键的用法保证了数据库里的数据都是一致的。比如你不能给一个不存在的课程加学生。
关系型数据模型就是现代数据库的基石。它简单、强大,非常适合存结构化数据。正如Edgar Codd说的:“整理好,要不然就等死!”(其实他原话没这么说,但意思差不多……)。下一讲我们会聊聊关系型模型和其他类型数据库(比如NoSQL)的区别,以及它们各自适合什么场景。
GO TO FULL VERSION