数据库的地基不复杂,但概念之间的层次关系必须理清:关系模型怎么组织数据、范式解决什么毛病、ER 图在设计中扮演什么角色、为什么最后要引出事务。这篇把这四个问题讲透。

关系模型:表、行、列与键

关系型数据库把数据组织成二维表。一套术语对应两层含义:

  • 表(关系,Relation):同一类实体的集合,比如学生表。
  • 行(元组,Tuple):一个实体的完整记录,比如一个学生的全部信息。
  • 列(属性,Attribute):实体的一个特征,比如姓名、学号;列有类型约束,全表同列同型。

「键」这一族概念用于标识和关联:

  • 候选键:能唯一标识一行的最小属性集合。学生表里「学号」可以,「身份证号」也可以——两者都是候选键。
  • 主键:从候选键中选定的一个,一张表只有一个主键,要求唯一且非空。工程上倾向选无业务含义、永不变化的值(自增 ID 或 UUID),避免业务字段变更牵连主键。
  • 外键:一张表中引用另一张表主键的列。订单表的 user_id 引用用户表主键,数据库据此强制引用完整性——不能给不存在的用户下单,也不能随手删掉已有订单的用户。

值得一提的工程分歧:高并发、分库分表场景下,不少团队禁用物理外键与级联操作,把一致性检查上移到应用层。这不是否定外键的语义,而是把强制力换了位置——逻辑关联必须在代码与对账任务里补偿回来。

三大范式:每个都配一个反例

范式要解决的问题是数据冗余,冗余的后果是三类异常:改一处漏改他处(更新异常)、想插的信息无处安放(插入异常)、删一行误删别的信息(删除异常)。

第一范式(1NF):列不可再分

要求每个字段只存一个原子值。

反例:学生表设计一个 phone 列,里面塞 "13800001111,13900002222" 两个号码。查询「手机号是 X 的学生」就无法用等值匹配,只能模糊扫描。

改造:一个字段只存一个号码;需要多个号码就拆出子表 student_phone(student_id, phone)。

第二范式(2NF):消除非主属性对键的部分依赖

前提是有联合主键。要求每个非主属性都依赖整个主键,而不是只依赖其中一部分。

反例:选课表以 (学号, 课程号) 为联合主键,却塞入 学生姓名、课程名 两列。姓名只由学号决定、课程名只由课程号决定——这就是部分依赖。后果:同一学生的姓名在表里重复出现几十次,改名要改一片。

改造:姓名归学生表、课程名归课程表,选课表只留 (学号, 课程号, 成绩)——成绩由整个联合键共同决定,是合法的。

第三范式(3NF):消除非主属性对键的传递依赖

要求非主属性之间不能互相决定。

反例:学生表含 (学号, 姓名, 系名, 系主任)。学号决定系名,系名又决定系主任——系主任通过系名传递依赖于学号。后果:系主任换人,要扫全表更新;系里暂时没有学生,系主任信息就无处安放。

改造:拆出系表 (系名, 系主任),学生表只留 系名 做关联。

满足 3NF 的设计基本消除了冗余与三类异常。但范式不是越多越好:每拆一张表,查询就多一次 JOIN。读多写少的互联网业务常做反范式设计——有意保留冗余字段(比如订单里冗余买家昵称)换读取性能,代价是靠应用逻辑或数据订正任务维护一致性。

ER 图:设计阶段的通用语言

ER 图(Entity Relationship Diagram)由三要素构成:实体(矩形,如学生、课程)、属性(椭圆,实体的特征)、联系(菱形,实体间的关系)。连线上标注数量对照关系:一对一、一对多、多对多。学生与课程就是典型的多对多,落到表设计时要加一个选课关联表来拆解。

ER 图的价值在于它是业务方与开发都能看懂的语言:需求评审时在图上对齐实体与关系,之后把实体转表、属性转列、联系转外键或关联表,设计就顺理成章。做项目之前先画 ER 图,是成本最低的返工保险。

为什么引出事务

表设计解决的是「数据怎么摆」,而真实系统还有另一个问题:「多个操作怎么绑在一起」。转账要同时扣 A 加 B,下单要同时写订单、减库存、清购物车——这些操作必须整体成功或整体失败,否则中间态被别的请求读到就是资损。这就是事务的动机。

事务的 ACID 四个特性可以一句话记住:原子性(all or nothing)、一致性(状态始终合法)、隔离性(并发互不干扰)、持久性(提交即落盘)。至于隔离级别、锁与 MVCC 这些并发控制的实现细节,属于 MySQL 章节的深水区,这里先把「为什么需要它」立住。

小结

  • 关系模型用表、行、列组织数据,用候选键/主键/外键标识并关联实体。
  • 三大范式层层递进:1NF 管原子性、2NF 管部分依赖、3NF 管传递依赖;反范式是用可控冗余换读性能。
  • ER 图是设计阶段的沟通工具,实体、属性、联系三要素直接映射到表结构。
  • 事务把多个操作绑成原子整体,ACID 是后续一切并发控制讨论的起点。