DBMS 中的依赖

2025年3月17日 | 阅读 15 分钟

DBMS 中的依赖是什么?

  • 依赖是一种约束,它控制或定义了两个或多个属性之间的关系。
  • 在数据库中,当同一表中记录的信息唯一地确定了存储在同一表中的其他信息时,就会发生这种情况。
  • 这也可能被描述为一种关系,在这种关系中,知道同一表中一个属性(或一组属性)的值会告诉你另一个属性(或一组属性)的值。
  • 理解数据库依赖关系至关重要,因为它们是数据库规范化的基础。

规范化代表什么?

规范化是数据库中组织数据的一种方法,有助于减少数据冗余、插入、更新和删除错误。它是基于函数关系和主键评估关系模式的过程。

这可以让你限制数据库占用的空间量,同时还可以确保数据被正确保存。

规范化的必要性

如前所述,规范化用于消除数据冗余。它提供了一种机制来消除数据库中的以下异常并使其更加一致。

数据库异常是由于准备不足和冗余引起的数据库故障。

  • 插入异常发生在我们无法将数据插入数据库时,因为在插入时缺少特定属性。
  • 更新异常发生在我们重复相同值的数据项但它们彼此不相关时。
  • 删除异常发生在我们删除一部分数据导致从数据库中删除其他必要信息时。

范式

如下面的图像所示,关系数据库中常用四种范式。

Dependency in DBMS
  1. 第一范式 (1NF)
    如果一个关系的所有属性都是单值的,或者它没有任何多值或复合属性,即每个属性都是原子属性,则该关系处于 1NF。
    如果存在复合属性或多值属性,则违反 1NF。为了解决这个问题,我们可以为多值属性的每个值创建一个新行,以将表转换为 1NF。
  2. 第二范式 (2NF)
    将 1NF 规范化为 2NF 关系涉及消除不完整的依赖。
    当任何非主属性(即不是候选键一部分的属性)没有完全函数依赖于候选键之一时,就会发生部分依赖。
    要达到第二范式,关系表必须遵循以下规则:
    • 表必须处于第一范式。
    • 它不得存在任何部分依赖,这意味着所有非主属性都必须完全函数依赖于主键。
  3. 第三范式 (3NF)
    将 2NF 规范化为 3NF 关系涉及消除传递依赖。
    要达到第三范式,关系表必须遵循以下规则:
    • 表应处于第二范式。
    • 不存在传递依赖于主键的非主属性。
    • 对于每个函数依赖 X -> Z,必须满足以下条件之一:
    • 表的主键是 X。
    • Z 是表的一个关键特征。
  4. Boyce-Codd 范式 (BCNF)
    Boyce-Codd 范式是 3NF 的一个更高级变体,因为它比 3NF 有更多的限制。
    要达到 Boyce-Codd 范式,关系表必须满足以下规则:
    • 表必须处于“第三范式”。
    • 对于每个非平凡函数依赖 X -> Y,X 是表的超键。也就是说,如果 Y 是主属性,X 不能是非主属性。

DBMS 中的依赖类型

在 DBMS 中,它有以下类型:

  • 函数依赖
  • 全函数依赖
  • 传递依赖
  • 多值依赖
  • 部分依赖

现在,让我们开始学习函数依赖。

函数依赖

函数依赖 (FD) 是数据库中两个属性之间存在的关系,通常是主键和其他非键属性。可以将其视为同一关系中两个特征之间的链接。

依赖用箭头“→”表示。

如果 C 函数地确定 D,则 C→D。

函数依赖,表示为 C→ D,是两个属性集 C 和 D 之间的关系。在这种情况下,C 被称为“决定因素”,D 被称为“依赖项”。

函数依赖有助于维护数据库数据的质量。

函数依赖规则

推理规则

  • 公理

可以使用阿姆斯特朗公理(一组推理规则)来推断关系数据库的函数依赖。它们是由 William W. Armstrong 创建的。

函数依赖公理

  1. 自反规则指出,如果 D 是 C 的子集,则 D 由 C 确定,即 C→D。
  2. 增广规则(也称为部分依赖规则)指出,如果 D 由 C 确定,那么对于任何 Z,CZ 确定 DZ。它规定每个非键属性都必须完全依赖于主键。
    即,如果 C→D,则对于任何 Z,CZ→DZ。
  3. 传递规则指出,如果 D 由 C 确定,Z 由 D 确定,那么 C 也必须确定 Z,即如果 C→D 且 D→Z,则 C→Z。
  • 分解

这是一条规定,如果一个表似乎包含由相同主键确定的两个实体,则应将其拆分为两个独立表。

根据此规则,如果 C 确定 D 和 Z,则 C 也分别确定 D 和 Z。即,如果 C→DZ,则 C→D 且 C→Z。

  • 并集

它表明,如果两个表是独立的但具有相同的属性,它们应该合并。它指出,如果 C 确定 D 且 C 确定 Z,则 C 必须确定 D 和 Z。

即,如果 C→D 且 C→Z,则 C→DZ。

条款

依赖项:它显示在函数依赖图的右侧。

决定因素:它显示在函数依赖图的左侧。

非规范化表:包含冗余数据的表。

示例

示例 1:在这里,我们有一个名为Student的表。

<Student>

StuIDStuNameStuAge
E01玫瑰14
E02Rolly13

在此,上表中StuName函数地依赖于StuID,因为对于给定的 StuID 值,StuName 只能接受一个值,即因为学生姓名可以从 ID 唯一确定,所以 StuName 可以被认为是依赖于 StuID。

但是,反向断言(StuName?>StuID)是错误的,因为多个学生可能具有相同的姓名但具有不同的 StuID。

示例 2:我们有一个表Employee。

<Employee>

Employee_NoE_NameE_Salary地址
1Dolly60000Seoul
2Flora (植物群)48000BukchonHanok
3Anni35000Seoul

我们可以从上面的表中推断出几个有效的函数依赖。

在这种情况下,知道 Employee_No 的值可以让我们访问 E_Name、Address、E_Salary 等。因此,Address、E Name 和 E Salary 都函数地依赖于 Employee No。

  • Employee_No→ {E_Name, E_Salary, Address}: 在这种情况下,Employee _No 可以决定字段 E_Name、E_Salary 和 Address 的值,从而产生合法的函数依赖。
  • Employee_No→E_Salary,因为 Employee_No 可以决定 {E_Name, E_Salary, 和 Address} 的整个集合,所以它也可以决定其子集 E_Salary。
  • 更多有效的函数依赖包括:Employee_No→name, {Employee_No, E_Name }→(E_Salary, Address} 等。

以下是一些无效的函数依赖

  • E_Name→E_Salary:这不是一个可接受的函数依赖,因为同名员工的薪资可能不同。
  • Address→E_Salary:同一地址的员工可能有不同的薪资;例如,上表中的 E_Salary 60000 和 35000 属于同一地址“Seoul”的员工;因此 Address→E_Salary 是一个不正确的函数依赖。
  • 更多无效的函数依赖包括:E_Name→Employee_No, {E_Name, E_Salary}→Employee_No 等。

函数依赖的类型

Dependency in DBMS

1. 琐碎函数依赖

  1. 琐碎函数依赖中的“依赖项”始终是“决定因素”的子集。
  2. 如果右侧的属性是左侧属性的子集,则称该函数依赖为琐碎的。
  3. 如果 D 是 C 的子集,则 C→D 被称为琐碎函数依赖。

示例:查看下面的 Student 表。

<Student>

Roll_NoS_NameS_Age
1John13
2Riya12
3Giya15
4Jolly16
  • 在这种情况下,{Roll_No, S_Name} →S_Name 是一个琐碎的函数依赖,因为依赖项 S_Name 是决定因素 {Roll_No, S_Name} 的子集。
  • { Roll_No } → { Roll_No }, { S_Name } → { S_Name } and { S_Age } → { S_Age } 也是琐碎的。

2. 非琐碎函数依赖

  • 它是琐碎函数依赖的逆。正式地,如果依赖项不是决定因素的子集,则称其为非琐碎函数依赖。
  • 如果 D 不是 C 的子集,则称 C→D 存在非琐碎函数依赖。非琐碎函数依赖定义为函数依赖 C→ D,其中 C 是一个属性集,D 也是一个属性集,但不是 C 的子集。

示例:查看下面的 Student 表。

<Student>

Roll_NoS_NameS_Age
1John13
2Riya12
3Giya15
4Jolly16
  • 在这种情况下,Roll_No→S_Name 是一个非琐碎的函数依赖,因为 S_Name(依赖项)不是 Roll_No(决定因素)的子集。
  • 类似地,{Roll_No, Name}→ Age 是非琐碎的函数依赖。

3. 多值函数依赖

  • 在多值函数依赖中,依赖集中的属性之间没有相互依赖关系。
  • 例如,如果 D 和 Z 之间没有函数依赖,则 C {D, Z} 被称为多值函数依赖。

示例:查看下面的Student表。

<Student>

Roll_NoS_NameS_Age
1John13
2Riya12
3Giya15
4Jolly16
  • 在这种情况下,{Roll_No}→ {S_Name, S_Age} 是一个多值函数依赖,因为“依赖值”S_Name 和 S_Age 之间不存在函数依赖(即 S_Name→S_Age 或 S_Age→S_Name 不存在)。

4. 传递函数依赖

  • 考虑两个函数依赖 C→ D 和 D→Z;根据传递性原理,必须存在 C→Z。这被称为传递函数依赖
  • 在传递函数依赖中,依赖项间接依赖于决定因素。

示例:考虑下面的 Student 表。

<Student>

Roll_NoS_NameS_DepartmentStreet_No
1JohnAC12
2RiyaBH11
3GiyaMV14
4JollyCD18
  • Roll_No→S_Department 和 S_Department→Street_No 在这里是正确的。因此,根据传递性原理,Roll_No→Street_Number 是一个有效的函数依赖。

函数依赖的好处

  • 函数依赖可防止数据重复。因此,同一数据不会在数据库中出现多次。
  • 它有助于维护数据库的数据质量。
  • 它有助于定义数据库语义和约束。
  • 它有助于发现有缺陷的设计。
  • 它有助于查找数据库设计信息。
  • 规范化方法始于识别关系中的潜在键。没有函数依赖,就无法找到候选键并规范化数据库。

全函数依赖

函数依赖 C→D,如果从 C 中移除任何属性 x,则“依赖”不再存在,则称其为全函数依赖

如果 D “完全函数依赖”于 C,则它不函数依赖于 C 的任何有效子集。

即,关系 CDE→Z 中的属性 Z“完全函数依赖”于 CDE,而不依赖于 CDE 的任何适当子集。也就是说,CDE 的子集(如 CD、DE、C、D 等)不能确定 Z。

另外;

  • 全函数依赖对应于第二范式规范化标准。
  • 函数依赖提高了我们数据库的数据质量。
  • 在此依赖中,非主属性函数依赖于候选键。
  • 数据库属性上的完全依赖有助于确保数据完整性并消除数据异常。

示例:在这里,我们有一个名为Supply的表。

<Supply>

Seller_IdProduct_idT_price
11530
21535
12100
22101
31342

根据表格,Seller_id 和 Product_id 都不能唯一确定价格,但 Seller_id 和 Product_id 结合起来可以。

因此,我们可以说 T_price“完全函数依赖”于 Seller_id 和 Product_id。

这概述并展示了我们的全函数依赖。

部分函数依赖

函数依赖 C → D,如果移除 C 中的任何属性 x 后依赖关系不再成立,则称其为部分函数依赖

函数依赖 C→Y,如果 D 函数依赖于 C 并且可以通过 C 的任何适当子集确定,则存在部分依赖。

即,我们有一个 CF→D、C→E 和 E→D 的关系。现在,让我们计算 {C+} 的闭包=CED。在这种情况下,C 可以独立地确定 D,这意味着 D 部分依赖于 CF。

另外;

  • 在部分函数依赖中,非主属性函数依赖于候选键的组成部分。
  • 第二范式的规范化标准不适用于部分函数依赖。另一方面,2NF 消除部分依赖。
  • 部分依赖的数据不会提高数据质量。在进行第二范式规范化之前必须将其删除。

部分依赖的原因

当我们看到上面的部分时,部分依赖发生在一个非主属性函数依赖于候选键的一部分。

换句话说,当表中的一个属性仅依赖于主键的一部分而不是整个键时,就会出现部分依赖。

示例:这里我们有一个名为Student的表。

<Student>

Roll_NoS_NameS_Course
1JohnDBMS
2RiyaC++
3GiyaJava
4JollyC

我们可以看到属性 S_Name 和 Roll_No 都可以唯一地标识 S_Course。因此,我们可以认为该关系部分依赖。

传递依赖

除了候选键之外,任何非主属性对另一个完全依赖于候选键的非主属性的依赖,都是一种传递依赖。

传递依赖发生在间接交互导致函数依赖时。因此,如果 C→ D 和 D→Z 为真,则 C→Z 是传递依赖。

传递依赖会导致数据库中的删除、更新和插入错误,被认为是糟糕的数据库设计。

要达到 3NF,首先必须消除传递依赖。

注意

只有当两个函数依赖建立间接函数依赖时,它才能是传递的。例如,

当以下函数依赖成立时,C →E 是传递依赖

  • C ->D
  • D 不意味着 C
  • C→E

只有在具有三个或更多属性的给定关系的情况下,才能轻松发生传递依赖。这种依赖性有助于我们将数据库规范化到其第三范式 (3NF)。

示例:这里我们有一个表Telecast_show

<Telecast_show>

Id_showId_telecastType_telecastCost_CD
F01S01Romantic30
F02S02Thriller50
F03S03Comedy20

(由于传递函数关系,上述表未达到 3NF。)

Id_show→Id_telecast

Id_telecast→Type_telecast

因此,以下函数依赖是传递的。

避免传递函数依赖

根据上述陈述,关系 <Telecast> 违反了 3NF(第三范式)。为了解决此违规,我们必须拆分表以消除传递函数关系。

<show>

Id_showId_telecastCost_CD
F01S0130
F02S0250
F03S0320

<telecast>

Id_telecastType_telecast
S09Thriller
S05Romantic
S09Comedy

上述关系现在处于规范化的第三范式 (3NF)。

多值依赖

多值依赖(Multivalued Dependency)是指一个表中有多个行。因此,它意味着该表中有许多其他行。因此,多值依赖将排除 4NF。任何多值依赖都将涉及至少三个表属性。

当给定表中的两个不同属性相互独立时,会发生多值依赖。然而,两者都依赖于第三个因素。多值依赖中至少有两个属性依赖于第三个属性。这就是为什么它总是涉及至少三个属性。

示例:这里我们有一个表Car。

<Car>

Model_carMonth_manuCol_or
S2001一月黄色
S2002二月红色
S2003三月黄色
S2004April红色
S2005可能黄色
S2006六月红色

在这种情况下,Col_or 和 Month_manu 列都依赖于 Model-car,但相互独立。因此,我们可以称这两个列为多值。因此,它们依赖于 Model_car。这是我们之前涵盖的依赖关系的图表。

为什么我们在 DBMS 中使用多值依赖?

当我们遇到这两种不同的方式时,我们总是使用多值条件。

  • 当我们想测试关系或确定它们在特定函数和多值依赖关系下的合法性时。
  • 当我们想知道对合法关系的排列存在哪些限制时;因此,我们只关注满足特定函数和多值依赖排列的关系。

发生情况

  • 当表中的两个属性相互独立但依赖于第三个属性时,这被称为多值依赖。
  • 由于多值依赖需要至少两个相互独立的属性才能依赖于第三个属性,因此所需的最少属性数为两个。

多值依赖的 DBMS 依赖条件

如果满足以下所有条件,我们可以说存在多值依赖。

如果对于任何关系 R,对于表中行 R1 和行 R2 中的所有成对数据值,属性‘C’有许多依赖于‘D’,并且存在表中的行 R3 和行 R4 之间的关系,使得

存在,并且在表中存在行 R3 和行 R4 之间的关系,使得

那么我们可以断定多值依赖 (MVD) 的存在。

也就是说,在行 R1、R2、R3 和 R4 中,

R1[C]、R2[C]、R3[C] 和 R4[C] 必须具有相同的值。

R1[D] 的值应等于 R3[D],R2[D] 的值应等于 R4[D]。

示例:这里我们有一个表Course。

<Course>

Row_Name_Course_work_Hobby_
R1RonitJavaDancing
R2RonitPython唱歌
R3RonitJavaDancing
R4RonitPython唱歌

因为对于 Name“Ronit”的相同值,我们有不同的 Course_work_ 和 Hobby_ 值,所以在 Name_ 上存在多值依赖。

验证<Course>表。

现在让我们检查表中的 MVD(多值依赖)条件。

条件 1

R1[C] = R2[C] = R3[C] = R4[C]

从表中;

R1[C] = R2[C] = R3[C] = R4[C] = 'Ronit'。

因此,条件 1 似乎已满足。

条件 2

R1[D] = R3[D], R2[D] = R4[D]

从表中;

R1[D] = R3[D] = 'Java', R2[D] = R4[D]= 'Python'。

因此,条件 2 也似乎已满足。

条件 3

R1[e] = R4[e], R2[e] = R3[e]

我们可以从表中得出结论。

R1[E] = R4[E] = 'Dancing', R2[E] = R3[E] = 'Singing'。

因此,条件 3 也得到满足,表明在给定情况下 MVD 发生了。

现在我们有;

并且我们从表中得到了以下内容;

Name_ →→Course_work_

并且对于 C →→ E,我们有

Name_ → Hobby_

最后,在给定的表中,我们可以得出条件关系为

结论

  • 关系的函数依赖定义了其属性如何相互关联。它有助于保留数据库中的数据质量。它用箭头“→”表示。
  • C→D 表示 C 对 D 的函数依赖。1974 年,William Armstrong 提出了一些关于函数依赖的公理或定律。它们是
    自反规则、增广规则和传递规则。
  • 函数依赖分为四类。函数依赖可分为琐碎、非琐碎、多值或传递。
  • 函数依赖有许多优点,包括保持数据库设计整洁、阐明数据库的含义和限制以及消除数据冗余。
  • 在数据库中,传递依赖是同一表中项目之间的间接关系,从而导致函数依赖。
  • 根据定义,传递依赖需要三个或更多属性。
  • 为了满足“第三范式 (3NF)”规范化标准,必须消除任何传递依赖。
  • 传递依赖会导致数据库中的删除、更新和插入错误,被认为是糟糕的数据库设计。
  • 当两个独立属性(例如 D 和 E)的值由第三个属性 C 确定时,就会发生多值依赖。
  • 多值依赖的符号是“C--> D”。
  • 因此,我们可以说,为了在关系 R 中存在多值依赖。
  • 一个属性的两个组成部分,例如 B 和 C,应该相互独立。
  • 对于 R 的两个元组,例如 C 和 D,C 的完整属性可能对组件 D 具有不同的值。
  • 类似地,对于 R 的两个元组,例如 C 和 E,组件 E 可能对 C 的完整属性具有不同的值。
  • 当数据库中的一个属性仅依赖于候选键的一部分而不是整个键时,这被称为部分函数依赖。即“主属性 → 非主属性”。
  • 范式用于消除冗余和最小化数据库存储。
  • 在 1NF 中,我们检查关系属性的原子性。
  • 在 2NF 中,我们查找关系中的部分依赖。
  • 在 3NF 中,我们查找关系中的传递依赖。
  • BCNF 在所有函数依赖项的 LHS 中查找超键。