欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 建筑 > 数据库系统概论(十七)超详细讲解数据库规范化与五大范式(从函数依赖到多值依赖,再到五大范式,附带例题,表格,知识图谱对比带你一步步掌握)

数据库系统概论(十七)超详细讲解数据库规范化与五大范式(从函数依赖到多值依赖,再到五大范式,附带例题,表格,知识图谱对比带你一步步掌握)

2025/6/8 9:00:52 来源:https://blog.csdn.net/2402_83322742/article/details/148456190  浏览:    关键词:数据库系统概论(十七)超详细讲解数据库规范化与五大范式(从函数依赖到多值依赖,再到五大范式,附带例题,表格,知识图谱对比带你一步步掌握)

数据库系统概论(十七)超详细讲解数据库规范化与五大范式(从函数依赖到多值依赖,再到五大范式,附带例题,表格,知识图谱对比带你一步步掌握)

  • 前言
  • 一、为什么需要规范化
    • 1. 我们先想一个问题:什么样的数据库表才算好表?
    • 2. 为什么会出现这些问题?
    • 3. 规范化的目标
    • 4. 规范化的核心逻辑
    • 5. 规范化总结
  • 二、函数依赖
    • 1. 函数依赖是什么?
    • 2. 平凡 vs 非平凡函数依赖
      • 2.1 平凡函数依赖「自己决定自己」
      • 2.2 非平凡函数依赖「决定新信息」
    • 3. 完全 vs 部分函数依赖
      • 3.1 完全函数依赖「缺一不可」
      • 3.2 部分函数依赖
    • 4. 传递函数依赖
    • 5. 函数依赖练习题讲解
      • 练习1:职工关系
      • 练习2:工程管理关系
    • 6. 一张图看懂函数依赖关系
  • 三、什么是码?
    • 1. 码的本质:
    • 2. 候选码、主码、主属性
      • 2.1 候选码
      • 2.2 主码
      • 2.3 主属性与非主属性
    • 3. 全码、外码
      • 3.1 全码
      • 3.2 外码
    • 4. 如何求候选码?
      • 步骤:
      • 实例1:职工表
      • 实例2:工程表
      • 实例3:WSC表
    • 总结码的分类与核心作用
  • 四、什么是范式?
  • 五、第二范式(2NF)
    • 1. 先搞懂第一范式(1NF)
    • 2. 1NF的问题
    • 3. 什么是第二范式(2NF)
      • 回顾完全依赖与部分依赖
    • 4. 用例子理解2NF
    • 5. 如何让表符合2NF?
    • 6. 2NF的效果和局限
  • 六、第三范式(3NF)
    • 1. 什么是3NF?
    • 2. 为什么需要3NF?
    • 3. 如何让表满足3NF?
        • 拆分后的两张表:
        • 拆分后的好处:
    • 4. 总结:
    • 5. 对比1NF→2NF→3NF:
  • 七、BCNF
    • 1. BCNF的核心定义
    • 2. BCNF的三个“必须”特点
    • 3. 通过例子理解BCNF(从符合到不符合)
      • 例子1:Course表(符合BCNF)
      • 例子2:Student表(符合BCNF)
      • 例子3:STJ表(不符合BCNF)
    • 4. BCNF的问题与解决
      • STJ表的问题(不符合BCNF的后果)
      • 解决方法:分解成两个BCNF表
    • 5. 3NF vs BCNF
    • 6. 什么时候需要用BCNF?
  • 八、多值依赖
    • 1. Teaching表的冗余困境
    • 2. 什么是多值依赖?
    • 3. 多值依赖 vs 函数依赖
    • 4. 平凡多值依赖 vs 非平凡多值依赖
    • 5. 多值依赖的特性
    • 6. 为什么多值依赖会导致问题?
    • 7. 如何解决多值依赖?
  • 九、4NF
    • 1. 4NF的定义
    • 2. 对比BCNF与4NF
    • 3. 案例分析:为什么Teaching表不满足4NF?
    • 2. 分解为4NF
    • 4. 例题:WSC表的分解
      • 4.1 原表结构:WSC(W, S, C)
  • 总结(核心概念速记):
    • 知识图谱


前言

  • 在前几期博客中,我们探讨了 SQL 连接查询,单表查询,嵌套查询,集合查询,基于派生表的查询,数据插入,修改与删除,空值的处理,视图,数据库安全性技术等知识点。
  • 从本节开始,我们将深入讲解数据库规范化与五大范式。

我的个人主页,欢迎来阅读我的其他文章
https://blog.csdn.net/2402_83322742?spm=1011.2415.3001.5343
我的数据库系统概论专栏
https://blog.csdn.net/2402_83322742/category_12911520.html?spm=1001.2014.3001.5482


一、为什么需要规范化

1. 我们先想一个问题:什么样的数据库表才算好表?

  • 假设你要设计一个学校教务系统的学生,需要记录「学号、学院、院长、课程、成绩」。

如果直接把这些信息堆到一张表里(比如下面这张表),乍一看好像没问题,但用起来就会发现许多的问题:

学号学院院长课程成绩
S1信息学院张明C195
S2信息学院张明C190
S3信息学院张明C188
…………………………

这张表有什么毛病?

  1. 数据冗余到爆炸:每个学生都重复记录「信息学院」「张明」,如果学院改名或换院长,要改几千条数据,漏改一条就出错!
  2. 插入/删除异常:如果一个新学院刚成立,还没有学生,这张表就没法记录学院和院长(因为学号是必填的);反之,如果某个学院的学生都毕业了,删除学生数据时,学院和院长的信息也会跟着消失。
  3. 更新麻烦:院长名字改了,需要把所有该学院学生的记录都改一遍,工作量大且容易漏。

2. 为什么会出现这些问题?

  • 上面的问题,本质是表中数据之间的「依赖关系」没设计好

什么是「数据依赖」?简单说就是:一个数据的决定了另一个数据的值
比如:

  • 学号 → 学院(一个学号只能属于一个学院)
  • 学院 → 院长(一个学院只有一个正职院长)
  • 学号+课程 → 成绩(一个学生选一门课只能有一个成绩)

但在最初的表中,「院长」依赖于「学院」,而「学院」又依赖于「学号」。

  • 这种多层依赖导致:
学号学院院长课程成绩
S1信息学院张明C195
S2信息学院张明C190
S3信息学院张明C188
…………………………
  • 只要号和课程存在,学院和院长就必须存在(插入异常);
  • 只要学号删除,学院和院长可能跟着消失(删除异常);
  • 学院或院长的修改需要波及所有相关学号(更新异常)。

3. 规范化的目标

规范化的目标:通过拆分表,消除不合理的数据依赖,让每张表只干一件事,避免冗余和异常。
比如上面的例子,把原来的「大杂烩表」拆成三张表:

学号学院院长课程成绩
S1信息学院张明C195
S2信息学院张明C190
S3信息学院张明C188
…………………………
  1. 学生表(学号,学院)—— 只记录学生属于哪个学院,学号唯一决定学院;
学号学院
S1信息学院
S2信息学院
S3信息学院
…………
  1. 学院表(学院,院长)—— 只记录学院和对应的院长,学院唯一决定院长;
学院院长
信息学院张明
…………
  1. 成绩表(学号,课程,成绩)—— 只记录学生选课的成绩,学号+课程唯一决定成绩。
学号课程成绩
S1C195
S2C190
S3C188
………………

这样拆分后

  • 数据冗余减少:院长名字只在学院表中出现一次;
  • 插入/删除正常:新学院没学生也能记录,学生毕业不影响学院信息;
  • 更新方便:改院长名字只需改学院表中的一条记录。

4. 规范化的核心逻辑

  1. 发现问题:观察表是否存在「数据冗余、插入/删除异常、更新麻烦」;
  2. 分析原因:检查数据之间的依赖关系是否「层级混乱」(比如间接依赖导致连锁反应);
  3. 应用规则:通过「范式」(1NF、2NF、3NF等)逐步拆分表,让每张表满足特定的依赖规则(比如「每个非主键字段只依赖于主键」)。

5. 规范化总结

想象一下,如果没有规范化:

  • 数据库会像一团乱麻,修改一个小数据可能引发连锁错误;

  • 数据冗余浪费存储空间,还可能导致「脏数据」(比如同个学院名有多个版本);

  • 插入和删除操作会受到不必要的限制(比如必须先有学生才能记录学院)。

  • 而规范化就像给数据库「分房间,每个房间(表)只放一类相关的数据,数据之间的依赖关系清晰简单。

  • 这样数据库才能又快又准地处理数据,这也是关系型数据库设计的核心思想之一。

二、函数依赖

1. 函数依赖是什么?

类比场景:就像「身份证号→姓名」,一个身份证号只能对应一个人,知道身份证号就能确定姓名。

定义:在表中,如果属性组 X 的值确定后,属性 Y 的值也被唯一确定,就称 X 函数决定 Y(记作 X→Y)。

函数依赖的特点

  • 唯一性:X 相同则 Y 必须相同(如学号相同,学院必须相同)。
  • 语义决定:依赖关系由业务规则决定(如“不允许重名”时,姓名→学号才成立)。

反例
下表中 Sno=S1 对应两个不同的 Sname,违背 Sno→Sname函数依赖

SnoSnameSsex
S1张三
S1李四

2. 平凡 vs 非平凡函数依赖

2.1 平凡函数依赖「自己决定自己」

场景:在组合键(如「学号+课程号」)中,部分属性决定自身。
例子

  • (学号,课程号)→ 学号
  • (学号,课程号)→ 课程号
    特点:Y 是 X 的一部分,无实际意义,所有表都默认存在。

2.2 非平凡函数依赖「决定新信息」

场景:组合键决定其他独立属性。
例子

  • (学号,课程号)→ 成绩(成绩是新信息,不在组合键中)

特点:需要重点关注,是数据库设计的核心

3. 完全 vs 部分函数依赖

3.1 完全函数依赖「缺一不可」

定义:组合键 X 的所有属性必须同时存在,才能决定 Y(缺少任何一个都不行)。
例子

  • (学号,课程号)→ 成绩
    ✅ 单独学号无法决定成绩(一个学生多门课成绩不同)
    ✅ 单独课程号无法决定成绩(一门课多个学生成绩不同)

标记X → F \overset{F}{\rightarrow} F Y

3.2 部分函数依赖

定义:组合键 X 中的某个单属性就能决定 Y,其他属性多余。
例子

  • (学号,课程号)→ 学院
    ❌ 单独学号就能决定学院(课程号无关)
    标记X → P \overset{P}{\rightarrow} P Y
    危害导致数据冗余(如一个学生选多门课,学院重复记录)。

4. 传递函数依赖

定义:若 X→YY→Z,但 Y 不能反推 X,则 X 传递决定 Z
例子

  • 学号→学院,学院→院长
    ✅ 学号→院长(通过学院间接决定)
    ❌ 学院不能反推学号(一个学院有多个学生)

标记X → T \overset{T}{\rightarrow} T Z

危害:更新异常(如院长离职,需修改所有该学院学生的记录)。

5. 函数依赖练习题讲解

关键符号注释

  • → F \overset{F}{\rightarrow} F:完全函数依赖
    例:组合键 (A,B) 必须全用上才能得到 C
  • → P \overset{P}{\rightarrow} P:部分函数依赖
    例:组合键 (A,B) 中,A 单独就能得到 C,B 多余
  • → T \overset{T}{\rightarrow} T:传递函数依赖
    例:A 决定 B,B 决定 C,但 B 不能决定 A,所以 A 传递决定 C

练习1:职工关系

题目描述
给定职工关系表如下,分析其中的函数依赖

职工号职工名年龄性别单位号单位名
E1ZHAO20FD3CCC
E2QIAN25MD1AAA

函数依赖

  1. 职工号→职工名/年龄/性别/单位号(职工号唯一)
  2. 单位号→单位名(单位不重名)
  3. 职工号 → T \overset{T}{\rightarrow} T 单位名(通过单位号传递)

练习2:工程管理关系

题目描述
给定工程管理关系表如下,分析其中的函数依赖

工程号材料号数量开工日期完工日期价格
P1I14200510200608250
P1I26200510200608300

函数依赖

  1. (工程号,材料号) → F \overset{F}{\rightarrow} F 数量(完全依赖,缺一不可)
  2. 工程号→开工日期/完工日期(部分依赖,单独工程号决定)
  3. 材料号→价格(单独材料号决定,与工程无关)

6. 一张图看懂函数依赖关系

分类类型核心定义典型例子记忆技巧
按内容有无意义平凡函数依赖Y 是 X 的一部分(自己决定自己的一部分)(学号, 课程号) → 学号
(A,B) → A
“多余的依赖”,默认存在,不用管
非平凡函数依赖Y 不是 X 的一部分(决定了新的信息)(学号, 课程号) → 成绩
(A,B) → C
“有用的依赖”,重点关注
----------------------------------------------------------------------------------------------------------------------------------------------------------
按依赖强度完全函数依赖X 的所有属性必须同时存在,才能决定 Y(缺一不可)(学号, 课程号) → F \overset{F}{\rightarrow} F 成绩“全靠组合键,少一个都不行”
部分函数依赖X 中的某个单属性就能决定 Y(其他属性多余)(学号, 课程号) → P \overset{P}{\rightarrow} P 学院“部分属性就够了,其他是摆设”
----------------------------------------------------------------------------------------------------------------------------------------------------------
按传递性传递函数依赖X 先决定 Y,Y 再决定 Z(Y 不能反推 X)学号 → 学院 → 院长 → 学号 → T \overset{T}{\rightarrow} T 院长“拐个弯才能决定,中间有跳板”

三、什么是码?

1. 码的本质:

在数据库中,就像“身份证号”,用来唯一标识一条数据记录

比如:

  • 一个班级里,每个学生有唯一的“学号”,学号就是区分学生的“码”。
  • 一张成绩单里,可能需要“学号+课程号”组合起来,才能唯一确定某个人的某门课成绩,这个组合就是“码”。

2. 候选码、主码、主属性

2.1 候选码

  • 定义:能唯一标识一条记录的最小属性或属性组合

    • “最小”意味着去掉任何一个属性,就无法唯一标识记录了。
  • 例子

    • 职工表(见下表)中,“职工号”唯一(E1、E2…不重复),因此职工号是候选码
    职工号职工名年龄性别单位号单位名
    E1ZHAO20FD3CCC
    • 工程表中,单独“工程号”或“材料号”都有重复(如P1对应I1、I2等),但工程号+材料号组合唯一,因此工程号+材料号是候选码
    工程号材料号数量开工日期完工日期价格
    P1I14200510200608250

2.2 主码

  • 定义:从多个候选码中选一个作为“主负责人”,用来代表该表的记录。
  • 特点
    • 每个表必须有且仅有一个主码
    • 主码的值不能重复、不能为空(就像学号不能重复,也不能没有学号)。
  • 例子
    职工号职工名年龄性别单位号单位名
    E1ZHAO20FD3CCC
    • 职工表中候选码只有“职工号”,因此主码就是职工号
    • 如果一个表有多个候选码(如学生表中“学号”和“身份证号”都是候选码),选其中一个作为主码即可。

2.3 主属性与非主属性

  • 主属性包含在任何一个候选码中的属性
    职工号职工名年龄性别单位号单位名
    E1ZHAO20FD3CCC
    • 例如职工表中“职工号”是候选码,因此“职工号”是主属性。
    • 工程表中“工程号”和“材料号”都是候选码的一部分,因此都是主属性。
  • 非主属性不包含在任何候选码中的属性
    • 例如职工表中的“职工名”“年龄”等,不能用来唯一标识记录,因此是非主属性。

3. 全码、外码

3.1 全码

  • 定义:当整个属性组(所有列)共同构成候选码时,称为全码。

  • 场景:表中没有任何单个或部分属性能唯一标识记录,必须用所有属性组合。

  • 例子
    在这里插入图片描述

    • 关系模式WSC(仓库W,保管员S,商品C)
      • 语义:每个仓库的每个保管员保管所有商品(如W1仓库的S1保管员保管C1、C2、C3)。
      • 分析:
        • 单独“W”无法唯一标识记录(W1对应多个S和C)。
        • “W+S”也无法唯一标识(W1+S1对应多个C)。
        • 必须用W+S+C三者组合才能唯一确定一条记录,因此全码是W+S+C

3.2 外码

  • 定义:当前表中的某个属性(或属性组)不是本表的码,但是另一个表的主码,称为外码。

  • 作用:用于建立表之间的关联(如职工表和单位表通过“单位号”关联)。

  • 例子

    职工号职工名年龄性别单位号单位名
    E1ZHAO20FD3CCC
    • 职工表中的“单位号”(D3、D1等)不是职工表的码(职工表的码是职工号),但它是“单位表”的主码(假设单位表用单位号唯一标识),因此单位号是职工表的外码

4. 如何求候选码?

步骤:

  1. 找唯一标识的属性/组合:看哪些列或列组合能唯一确定一行数据。
  2. 验证最小性:去掉其中一个属性,看是否还能唯一标识(能的话就不是最小组合)。

实例1:职工表

职工号职工名年龄性别单位号单位名
E1ZHAO20FD3CCC
  • 列:职工号、职工名、年龄、性别、单位号、单位名
  • 唯一列:职工号(无重复)
  • 结论:候选码=职工号

实例2:工程表

工程号材料号数量开工日期完工日期价格
P1I14200510200608250
P1I26200510200608300
  • 列:工程号、材料号、数量、开工日期、完工日期、价格
  • 单独列:工程号(重复,如P1出现多次),材料号(重复,如I1出现多次)
  • 组合列:工程号+材料号(唯一,每个组合对应唯一一行)
  • 结论:候选码=工程号+材料号

实例3:WSC表

在这里插入图片描述

  • 列:W(仓库)、S(保管员)、C(商品)
  • 单独列:W、S、C均重复(如W1对应多个S和C)
  • 两列组合:W+S(对应多个C),W+C(对应多个S),S+C(对应多个W)
  • 三列组合:W+S+C(唯一)
  • 结论:全码=W+S+C

总结码的分类与核心作用

类型定义例子(职工表)
候选码能唯一标识记录的最小属性/组合职工号
主码从候选码中选一个作为代表职工号(唯一候选码,直接选)
主属性包含在候选码中的属性职工号
全码所有属性共同构成候选码WSC表中的W+S+C
外码本表中非码属性,但是另一个表的主码单位号(对应单位表的主码)

四、什么是范式?

为什么需要范式?

假设你设计了一张“学生选课表”,记录学生、课程和成绩,但发现:
在这里插入图片描述

  1. 数据冗余:同一个学生的姓名、班级重复出现多次。
  2. 插入异常:如果一个学生还没选课,就无法记录他的姓名和班级。
  3. 更新麻烦:修改学生班级时,需要更新所有相关行,容易漏改。
  4. 删除风险:删除某门课的所有记录,可能连学生信息也一起删掉了。

范式就是一套规则,用来规范表格设计,解决上述问题。

核心思路:通过“分表”(模式分解),让表格更“纯净”,减少冗余和异常。

五、第二范式(2NF)

1. 先搞懂第一范式(1NF)

1NF是关系型数据库的最低门槛,它只有一个要求:

  • 表中每个字段(属性)必须是最小单元,不能再拆分
    ✅ 正确示例(职工表):

    职工ID姓名年龄
    001张三25
    (每个字段都是“不可分割”的数据,比如“姓名”不能拆成“姓”和“名”存放在同一列)

    ❌ 错误示例(科目余额表):

    科目余额(元/角)
    现金100/5
    (“余额”拆成了“元”和“角”,违反1NF,不能称为合法的关系表)

2. 1NF的问题

即便满足1NF,表结构仍可能有问题。比如:
学生选课表(S-L-C)(仅满足1NF):

学号(Sno)学院(School)宿舍(Sloc)课程号(Cno)成绩(Grade)
S1信息学院2号楼C389
S2信息学院2号楼C297
S3计算机学院3号楼C186

看起来没问题,但藏着3个大坑:

  • 数据冗余:同一个学院的学生,“学院”和“宿舍”反复重复(如信息学院重复多次)。
  • 插入异常:如果一个学生还没选课(Cno为空),就无法插入这条记录(因为“学号+课程号”是主键,不能有空)。
  • 删除异常:如果删除某门课程的所有记录,可能连学生的学院和宿舍信息也一起删掉了。

3. 什么是第二范式(2NF)

2NF的核心规则

  • 前提:必须先满足1NF。
  • 规则:表中非主属性(不是主键的字段)必须完全依赖于主键,不能只依赖主键的“一部分”。

回顾完全依赖与部分依赖

  • 主键(候选码):能唯一标识一条记录的字段或字段组合(比如“学号+课程号”)。
  • 完全依赖:非主属性必须依赖于整个主键,缺一不可。
    例:成绩(Grade)必须由“学号+课程号”共同决定(一个学生选不同课程有不同成绩)。
  • 部分依赖:非主属性只依赖于主键的一部分
    例:学院(School)只依赖于“学号”(一个学生属于一个学院,和课程无关),这就是“部分依赖”(依赖主键中的“学号”,而非整个“学号+课程号”)。

4. 用例子理解2NF

表结构

学号(Sno)学院(School)宿舍(Sloc)课程号(Cno)成绩(Grade)
S1信息学院2号楼C389
S2信息学院2号楼C297
S3计算机学院3号楼C186
  • 主键:(学号,课程号)(Sno, Cno)
  • 非主属性:学院(School)、宿舍(Sloc)、成绩(Grade)

函数依赖关系

  • 成绩完全依赖主键:(学号, 课程号) → 成绩(必须两个字段一起才能确定成绩)。
  • 学院部分依赖主键:学号 → 学院(只用学号就能确定学院,课程号多余)。
  • 宿舍通过学院传递依赖学号:学号 → 学院 → 宿舍(本质还是部分依赖主键中的学号)。

结论:存在非主属性(学院、宿舍)对主键的部分依赖,所以 S-L-C表只满足1NF,不满足2NF

5. 如何让表符合2NF?

解决思路:把有部分依赖的字段拆到另一个表,确保每个表的非主属性都完全依赖主键。
拆分后的两张表:

表1:学生选课表(SC)—— 专注成绩

学号(Sno)课程号(Cno)成绩(Grade)
S1C389
S2C297
  • 主键:(学号,课程号)
  • 非主属性:成绩(完全依赖主键,符合2NF)。

表2:学生学院表(S-L)—— 专注学院和宿舍

学号(Sno)学院(School)宿舍(Sloc)
S1信息学院2号楼
S3计算机学院3号楼
  • 主键:学号(单个字段为主键)
  • 非主属性:学院、宿舍(完全依赖学号,符合2NF)。

6. 2NF的效果和局限

拆分后的好处

  • 数据冗余减少:学院和宿舍信息只存一次,不再随课程重复。
  • 插入/删除更灵活:学生没选课时,可先在S-L表插入学号、学院等信息;删除课程不影响学生基本信息。

但2NF不是终点

  • S-L表中仍存在“传递依赖”:学号 → 学院 → 宿舍(宿舍依赖学院,学院依赖学号),这会导致新的冗余(如学院搬迁,所有该学院学生的宿舍都要修改)。
  • 后续需要3NF进一步优化

六、第三范式(3NF)

2NF解决了「部分函数依赖」的问题,但可能还存在「传递函数依赖」的问题,而 3NF就是用来解决这个问题的

1. 什么是3NF?

一句话总结
如果一个表满足 2NF,并且 非主属性之间不能有「传递依赖」,那它就属于 3NF

关键概念

  • 传递依赖:如果 A → BB → C,且 B 不能反过来决定 A,那么 C 就通过 B 传递依赖于 A
    (比如:“学生学号 → 学院 → 学院地址”,“学院地址”就传递依赖于“学生学号”)

2. 为什么需要3NF?

假设我们有一个满足 2NF 的表 S-L(Sno, School, Sloc)学生学号,学院,学院地址):

SnoSchoolSloc
S1信息学院教学楼2
S2信息学院教学楼2
S3计算机学院教学楼3

这个表存在什么问题?

  1. 数据冗余:同一个学院的地址重复出现(比如“信息学院”的地址重复多次)。
  2. 更新麻烦:如果信息学院搬了新地址,需要修改所有相关行,漏改就会数据不一致。
  3. 插入/删除异常
    • 插入:如果新成立一个学院但还没有学生,无法插入学院和地址(因为学号是主键,不能为空)。
    • 删除:如果删除某个学院的所有学生,学院和地址信息也会被删掉。

问题的根源传递函数依赖

  • 表中的函数依赖关系:
    • Sno → School(学号决定学院)
    • School → Sloc(学院决定地址)
    • 因此:Sno → School → Sloc,即 Sloc(地址)通过 School(学院)传递依赖于 Sno(学号)
    • 这违反了 3NF 的要求(非主属性不能传递依赖于主键)。

3. 如何让表满足3NF?

解决方法:把有传递依赖的表拆分成两张表,消除传递依赖。

拆分后的两张表:
  1. 学生-学院表 S-D(Sno, School)

    SnoSchool
    S1信息学院
    S2信息学院
    S3计算机学院
    • 主键:Sno
    • 依赖关系:Sno → School(直接依赖,无传递)
  2. 学院-地址表 D-L(School, Sloc)

    SchoolSloc
    信息学院教学楼2
    计算机学院教学楼3
    • 主键:School
    • 依赖关系:School → Sloc(直接依赖,无传递)
拆分后的好处:
  1. 数据冗余减少:学院地址只在 D-L 表中存一次。
  2. 更新方便:修改学院地址时,只需改 D-L 表中的一行。
  3. 插入/删除正常
    • 可以先插入学院和地址(即使没有学生)到 D-L 表。
    • 删除学生时,不影响学院和地址信息。

4. 总结:

  1. 3NF是2NF的升级版
    • 先满足 1NF(属性不可拆分),再满足 2NF(消除部分依赖),最后满足 3NF(消除传递依赖)。
  2. 核心原则
    • 非主属性必须直接依赖于主键,不能通过其他非主属性间接依赖。
  3. 不足
    • 3NF 不能完全消除所有问题(比如多值依赖,需要更高的范式如 BCNF),但对大多数业务场景已足够。

5. 对比1NF→2NF→3NF:

范式解决的问题举例(学生相关表)
1NF属性不可拆分把“姓名+电话”拆成独立字段
2NF消除部分依赖把“学生-课程-学院”拆成学生课程表和学生学院表
3NF消除传递依赖把“学生-学院-地址”拆成学生学院表和学院地址表

一句话记忆

  • 1NF:字段不能再分;
  • 2NF:主键能完全决定所有非主属性;
  • 3NF:非主属性之间不能“接力决定”。

七、BCNF

1. BCNF的核心定义

BCNF是比3NF更严格的数据库设计规范,它的核心要求就一句话:
每个能“决定”其他属性的属性或属性组(决定因素),都必须包含码(主键或候选键)
用大白话来讲就是:

如果属性X能唯一确定属性Y(即X→Y),那么X必须是“老大”(码),不能是“小弟”(非码属性)。

2. BCNF的三个“必须”特点

特点3NFBCNF
非主属性依赖消除了对码的部分依赖和传递依赖同样满足
主属性依赖可能存在主属性对码的部分/传递依赖必须消除主属性对码的部分/传递依赖
决定因素要求允许非码的决定因素存在禁止非码的决定因素存在

关键区别

  • 3NF只约束“非主属性”,而BCNF同时约束“主属性”和“决定因素”。
  • 可以说,BCNF是3NF的“加强版”,解决了3NF可能残留的依赖问题。

3. 通过例子理解BCNF(从符合到不符合)

例子1:Course表(符合BCNF)

Course(Cno, Cname, Ccredit, Cpno)
CnoCnameCcreditCpno
C001数据库基础3NULL
C002数据结构4C001
C003操作系统3C002
C004计算机网络3C001
C005软件工程4C003
  • :Cno(课程号)
  • 函数依赖
    Cno→Cname(课程号决定课程名)
    Cno→Ccredit(课程号决定学分)
    Cno→Cpno(课程号决定先修课)
  • 分析
    所有决定因素都是码(Cno),满足“决定者必须是老大”,所以 Course∈BCNF

例子2:Student表(符合BCNF)

Student(Sno, Sname, Ssex, Sbirthdate, Smajor)
SnoSnameSsexSbirthdateSmajor
S1张三2003-05-12信息管理与信息系统
S2李四2004-02-28数据科学与大数据技术
S3王五2003-11-03计算机科学与技术
S4赵六2004-08-15软件工程
S5陈七2003-07-09信息安全
  • 业务规则:学生不重名,所以 候选码有两个:Sno和Sname
  • 函数依赖
    Sno→Sname, Ssex,…(学号决定其他属性)
    Sname→Sno, Ssex,…(姓名决定其他属性)
  • 分析
    无论用Sno还是Sname作为决定因素,它们都是码,因此 Student∈BCNF

例子3:STJ表(不符合BCNF)

STJ(S, T, J) (学生,教师,课程)
STJ
001T1操作系统
001T2微机原理
001T3数据结构
002T4操作系统
003T1操作系统
004T1操作系统
………………
  • 业务规则
    • 每个教师只教一门课(T→J)
    • 每门课可由多个教师授课
    • 学生选课后,教师和课程相互确定(S+J→T,S+T→J)
  • 候选码:(S,J) 和 (S,T)(两个属性组合才能唯一确定一条记录)
  • 函数依赖
    • (S,J)→T(学生+课程决定教师)
    • (S,T)→J(学生+教师决定课程)
    • T→J(教师决定课程,重点!)
  • 问题
    • 决定因素T(教师)不是码(码是S+J或S+T),但T→J成立。
    • 这违反了BCNF的规则:非码的T居然能决定J
  • 结论STJ∉BCNF,但STJ∈3NF(因为非主属性不存在传递依赖)。

4. BCNF的问题与解决

STJ表的问题(不符合BCNF的后果)

  • 数据冗余:教师T1教课程J1,若有100个学生选T1的课,J1会重复100次。
  • 更新麻烦:若T1改教J2,需修改所有相关记录,否则数据不一致。
  • 插入/删除异常:新教师还没学生选课时,无法插入其授课信息。

解决方法:分解成两个BCNF表

  1. ST表(学生-教师)
    ST(S, T) (候选码:(S,T))
    函数依赖:(S,T)→ 无其他属性(直接依赖码)
    
  2. TJ表(教师-课程)
    TJ(T, J) (候选码:T)
    函数依赖:T→J(决定因素T是码,符合BCNF)
    
  • 结果
    • 每个表的决定因素都是码,ST∈BCNF,TJ∈BCNF
    • 数据冗余和异常问题消失。

5. 3NF vs BCNF

  • 3NF:只保证“非主属性不依赖非码”,但允许“主属性依赖非码”。
  • BCNF:进一步要求“所有决定因素必须是码”,彻底消除主属性和非主属性对非码的依赖。

关系

  • 所有BCNF表都属于3NF,但3NF表不一定属于BCNF。
  • BCNF是函数依赖范围内“最彻底”的规范化,能最大程度避免数据问题。

6. 什么时候需要用BCNF?

  • 当你的表中存在“主属性依赖非码属性”时(如STJ中的T→J),就需要用BCNF规范来分解表。
  • 大部分业务场景中,3NF已足够,但在高并发、数据敏感的系统(如金融、医疗)中,常需进一步优化到BCNF。

八、多值依赖

1. Teaching表的冗余困境

假设我们有一张 课程-教员-参考书表(Teaching),记录每门课程的授课老师和使用的参考书:

课程(C)教员(T)参考书(B)
物理李勇普通物理学
物理李勇光学原理
物理李勇物理习题集
物理王军普通物理学
物理王军光学原理
物理王军物理习题集
数学李勇数学分析

这张表看起来符合BCNF,却有大问题:

  1. 数据爆炸式冗余
    • 物理课有2个老师,3本参考书,导致 2×3=6条记录,每增加一个老师或参考书,记录数就会相乘增长。
  2. 更新麻烦
    • 若物理课新增一本参考书,需要为每个老师单独新增一条记录(如李勇+王军都要关联新书)。
  3. 插入/删除限制
    • 新增老师时,必须同时关联所有参考书;删除某本参考书时,可能误删其他老师的关联记录。

为什么BCNF解决不了这个问题?
因为这里的问题不是函数依赖(如“课程→教员”不成立,一门课有多个教员),而是 多值依赖(Multiple-Valued Dependency)。

2. 什么是多值依赖?

定义
当表中存在三个属性 X、Y、Z,且满足:

  • 给定一个 X 值,对应的 Y 值与 Z 值无关,即 YZ 各自独立地“多对多”依赖于 X
    这种依赖关系称为 多值依赖,记作 X →→ Y(读作“X多值决定Y”)。

举个例子

  • X=课程(C)Y=教员(T)Z=参考书(B)
课程(C)教员(T)参考书(B)
物理李勇普通物理学
物理李勇光学原理
物理李勇物理习题集
物理王军普通物理学
物理王军光学原理
物理王军物理习题集
数学李勇数学分析
  • 对于课程“物理”(X=物理):
    • 教员集合 {李勇, 王军} 只与课程有关,与参考书无关(不管用什么书,教员都是这两人)。
    • 参考书集合 {普通物理学, 光学原理, 物理习题集} 也只与课程有关,与教员无关(不管谁来教,书都是这几本)。
  • 因此:C →→ TC →→ B(课程多值决定教员和参考书)。

3. 多值依赖 vs 函数依赖

类型依赖关系例子(Teaching表)
函数依赖X → Y(X唯一决定Y)若“课程→学分”,则一门课只有一个学分
多值依赖X →→ Y(X决定一组Y值)一门课可以有多个教员,且与参考书无关

核心区别

  • 函数依赖是“一对一”或“一对多”,多值依赖是“一对多对多”(Y和Z互相独立)。
  • 多值依赖中,Y的取值只与X有关,与Z无关;反之亦然。

4. 平凡多值依赖 vs 非平凡多值依赖

  • 平凡多值依赖:若 Y是X的子集(Y⊆X),或 Y∪X=U(Y和X包含所有属性),则依赖无实际意义。
    • 例:表中若有“学生S→→课程 C”(课程是学生的属性),属于平凡依赖。
SC
S1数学
S1英语
S2数学
S2英语
  • 非平凡多值依赖:Y既不是X的子集,也不包含所有其他属性。
课程(C)教员(T)参考书(B)
物理李勇普通物理学
物理李勇光学原理
物理李勇物理习题集
物理王军普通物理学
物理王军光学原理
物理王军物理习题集
数学李勇数学分析
  • Teaching表中的 C→→TC→→B 均为非平凡多值依赖(T和B都不是C的子集,且还有其他属性)。

5. 多值依赖的特性

  1. 对称性:若 X→→Y,则 X→→Z(Z是除X、Y外的属性)。
    • Teaching表中,C→→T成立,则C→→B必然成立(Z=B)。
课程(C)教员(T)参考书(B)
物理李勇普通物理学
物理李勇光学原理
物理李勇物理习题集
物理王军普通物理学
物理王军光学原理
物理王军物理习题集
数学李勇数学分析
  1. 传递性:若 X→→YY→→Z,则 X→→Z-Y

    • (较复杂,可暂不深究,记住多值依赖可传递即可)
  2. 函数依赖是多值依赖的特例:若 X→Y,则必然有 X→→Y

    • 例:“学号→姓名”是函数依赖,也是平凡多值依赖(Y⊆X吗?不,这里Y是姓名,X是学号,所以是特殊的多值依赖)。

6. 为什么多值依赖会导致问题?

Teaching表的问题根源在于:

  • 教员和参考书之间没有直接关系,它们的组合(如“李勇+普通物理学”、“王军+光学原理”)是“多余的”,仅因课程关联而被迫存在。
  • 这种“无关属性的强行组合”导致数据冗余,而BCNF无法处理这种依赖(BCNF只约束函数依赖)。

7. 如何解决多值依赖?

步骤:将存在非平凡多值依赖的表分解为两张表,消除依赖。
Teaching表分解后

  1. 课程-教员表(C-T)
    课程(C)教员(T)
    物理李勇
    物理王军
    • 依赖:C→→T(多值依赖存在,但表中仅两列,属于平凡多值依赖,无冗余)。
  2. 课程-参考书表(C-B)
    课程(C)参考书(B)
    物理普通物理学
    物理光学原理
    • 依赖:C→→B(同理,平凡多值依赖)。

效果

  • 记录数从6条减少到2+3=5条(实际业务中数据量越大,优化越明显)。
  • 新增教员或参考书时,只需在对应表中单独操作,无需交叉组合。

九、4NF

1. 4NF的定义

关系模式R满足:所有非平凡多值依赖的“决定因素”X都必须包含码,则R∈4NF。

  • :能唯一确定一条记录的属性或属性组(如“学号”是学生表的码)。
  • 核心要求:不允许存在“非平凡且非函数依赖的多值依赖”。

2. 对比BCNF与4NF

范式处理对象要求
BCNF函数依赖所有非平凡函数依赖的决定因素是码
4NF多值依赖所有非平凡多值依赖的决定因素是码
  • 关系:4NF是BCNF的“升级版”,先满足BCNF,再处理多值依赖。

3. 案例分析:为什么Teaching表不满足4NF?

  • 数据示例
    C(课程)T(教师)B(教材)
    物理李勇普通物理学
    物理李勇光学原理
    物理王军普通物理学
    物理王军光学原理
  • 问题
    • 存在非平凡多值依赖:C→→T 和 C→→B(T和B独立,且C不是码)。
    • :(C, T, B)(三者组合唯一,但单个C无法确定记录)。
    • 结论:Teaching∈BCNF(无不良函数依赖),但∉4NF(存在非平凡多值依赖且决定因素无码)。

2. 分解为4NF

  • CT表(C, T)

    C(课程)T(教师)
    物理李勇
    物理王军
    数学李勇
    • 多值依赖:C→→T(平凡,因C∪T={C,T}=表属性),允许存在。
    • :(C, T)(但决定因素C虽非码,依赖是平凡的,符合4NF)。
  • CB表(C, B)

    C(课程)B(教材)
    物理普通物理学
    物理光学原理
    数学数学分析
    • 多值依赖:C→→B(平凡,因C∪B={C,B}=表属性),允许存在。
    • 结论:CT和CB均∈4NF,消除了多值依赖带来的冗余。

4. 例题:WSC表的分解

4.1 原表结构:WSC(W, S, C)

WSC
W1S1C1
W1S1C2
W1S2C1
W1S2C2
W2S3C3
W2S3C4
W2S4C3
W2S4C4
  • 含义:W(仓库)、S(保管员)、C(商品),一个仓库有多个保管员和商品,且保管员与商品无关。
  • 问题
    • 非平凡多值依赖:W→→S 和 W→→C(W不是码,码是(W, S, C))。
    • 分解:拆分为WS(W, S)和WC(W, C),每个表中的多值依赖变为平凡(如W→→S在WS表中是平凡的),满足4NF。

总结(核心概念速记):

核心概念速记
数据库规范化 = 数据依赖分析 + 范式分层约束 + 模式分解实践

  • 规范化目标

    • 消除数据冗余、插入/删除异常、更新异常,通过模式分解让表结构更“纯净”。
    • 核心逻辑:发现依赖层级混乱 → 应用范式规则 → 逐步拆分表。
  • 数据依赖体系

    • 函数依赖:X→Y(X唯一决定Y),分为平凡/非平凡、完全/部分、传递三类。
    • 多值依赖:X→→Y(X决定一组独立的Y值,与其他属性无关)。
  • 范式阶梯(从低到高)

    范式核心规则解决的问题
    1NF属性不可拆分(最低要求)字段原子性
    2NF非主属性完全依赖主键(消除部分依赖)部分依赖导致的冗余
    3NF非主属性无传递依赖(消除传递依赖)传递依赖导致的冗余
    BCNF所有决定因素包含码(强化3NF,约束主属性依赖)主属性对非码的依赖
    4NF非平凡多值依赖的决定因素包含码(处理多值依赖)多值依赖导致的爆炸式冗余

规范化关键对比

问题类型依赖类型解决范式典型分解案例
字段可拆分1NF拆“姓名+电话”为独立字段
部分依赖非主属性依赖主键部分属性2NF学生选课表拆分为SC(成绩)和S-L(学院)
传递依赖非主属性→非主属性→码3NF学生学院表拆分为S-D(学生-学院)和D-L(学院-地址)
主属性依赖非码主属性→非码属性BCNFSTJ表拆分为ST(学生-教师)和TJ(教师-课程)
多值依赖冗余非平凡多值依赖4NFTeaching表拆分为CT(课程-教师)和CB(课程-教材)

知识图谱

数据库规范化与五大范式  
├─ 规范化基础  
│  ├─ 问题驱动:冗余/异常 → 依赖分析  
│  ├─ 函数依赖:平凡/非平凡、完全/部分、传递  
│  └─ 码体系:候选码/主码/全码/外码  
├─ 范式阶梯  
│  ├─ 1NF:属性原子性  
│  ├─ 2NF:消除部分依赖  
│  ├─ 3NF:消除传递依赖  
│  ├─ BCNF:强化决定因素约束  
│  └─ 4NF:处理多值依赖  
├─ 核心操作  
│  ├─ 模式分解:垂直拆分(按依赖类型)  
│  └─ 依赖验证:通过函数依赖图/多值依赖表  
└─ 典型场景  ├─ 学生管理:从1NF到3NF的逐步优化  ├─ 课程教学:BCNF与4NF的多表分解  └─ 多对多关系:通过全码/外码建立关联  

重点提炼

  1. 函数依赖核心判断

    • 完全依赖:组合键缺一不可(如学号+课程号→成绩)。
    • 传递依赖:中间有“跳板”属性(如学号→学院→院长)。
  2. 范式升级关键点

    • 2NF vs 3NF:前者处理部分依赖,后者处理传递依赖。
    • BCNF vs 3NF:前者约束所有决定因素(含主属性),后者仅约束非主属性。
    • 4NF独特点:专门解决多值依赖导致的“属性独立组合冗余”。
  3. 分解原则

    • 保持函数依赖:分解后原依赖关系不丢失。
    • 无损连接:分解后的表通过自然连接可还原原表数据。
  4. 应用建议

    • 一般业务达到3NF即可满足需求。
    • 高并发或数据敏感系统(如金融、电商)需考虑BCNF/4NF

依赖类型与范式对应表

依赖类型是否允许存在(各范式)处理方式
平凡函数依赖所有范式均允许无需处理
非平凡函数依赖需决定因素是码(BCNF+)分解表使决定因素包含码
部分函数依赖1NF允许,2NF+禁止拆分表消除对主键部分依赖
传递函数依赖1NF/2NF允许,3NF+禁止拆分表打断传递链
非平凡多值依赖BCNF允许,4NF禁止拆分表使多值依赖平凡化

技术演进脉络

表设计演进 —— 大杂烩表(1NF) → 消除部分依赖(2NF) → 消除传递依赖(3NF)  ↓                ↓                  ↓  ↓                ├─ 强化主属性约束(BCNF) → 处理多值依赖(4NF)  ↓                ↓  
应用场景 —— 简单业务       → 复杂业务(含多对多关系) → 高并发/高冗余场景  

经典例题速解

例题:判断关系模式R(A,B,C,D),若函数依赖为A→B, B→C,码为A,属于第几范式?
分析

  • 非主属性C通过B传递依赖于A(A→B→C),存在传递依赖。
  • 结论:满足2NF(非主属性完全依赖A),但不满足3NF(存在传递依赖),故R∈2NF。

以上就是这篇博客的全部内容,下一篇我们将继续探索更多精彩内容。

我的个人主页,欢迎来阅读我的其他文章
https://blog.csdn.net/2402_83322742?spm=1011.2415.3001.5343
我的数据库系统概论专栏
https://blog.csdn.net/2402_83322742/category_12911520.html?spm=1001.2014.3001.5482

非常感谢您的阅读,喜欢的话记得三连哦

在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词