30

我的数据库设计中有一些传递依赖项。我的上级告诉我,这些可能会导致错误。我发现很难找到能够告诉我这些依赖项将如何导致错误的资源。它们会带来什么样的问题?

我不是在争论这个事实,只是渴望了解它们会引起什么样的问题。

编辑以获取更多详细信息:

来自维基百科:

传递依赖
传递依赖是一种间接的函数依赖,其中 X→Z 仅凭借 X→Y 和 Y→Z。

4

4 回答 4

62

我将通过一个例子来解释:

-------------------------------------------------------------------
|  Course  |    Field     |   Instructor   |  Instructor Phone    |
-------------------------------------------------------------------
|  English |  Languages   |  John Doe      |     0123456789       |
|  French  |  Languages   |  John Doe      |     0123456789       |
|  Drawing |  Art         |  Alan Smith    |     9856321158       |
|  PHP     |  Programming |  Camella Ford  |     2225558887       |
|  C++     |  Programming |  Camella Ford  |     2225558887       |
-------------------------------------------------------------------
  • 如果你有一个Course你可以很容易地得到它的Instructorso Course->Instructor
  • 如果你有一个Instructor你不能得到他的Course,因为他可能正在教不同的课程。
  • 如果你有一个Instructor你可以很容易地得到他的Phoneso Instructor->Phone

这意味着如果你有一个Coursethen 你可以得到Instructor Phonewhich 意味着 Course->Instructor Phone(即传递依赖)

现在解决问题:

  1. 如果您同时删除FrenchEnglish课程,那么您也将删除他们的讲师John Doe,并且他的电话号码将永远丢失。
  2. 除非您先为他添加一个新的,否则没有办法向Instructor您的数据库添加一个新的Course,或者您可以将数据复制到一个Instructors table更糟糕的地方。
  3. 如果讲师John Doe更改了他的电话号码,那么您将不得不使用新信息更新他教授的所有课程,这很容易出错。
  4. 除非您删除他教授的所有课程或将他的所有字段设置为空,否则您无法从数据库中删除讲师。
  5. 如果您决定保留导师的出生日期怎么办?您必须在表格中添加一个Birth Date字段。Courses这听起来合乎逻辑吗?为什么首先要在课程表中保留讲师信息?
于 2012-03-30T21:47:28.463 回答
17

表达 3NF 的一种方法是:

所有属性都应该依赖于密钥、整个密钥,而只有密钥。

传递依赖 X->Y->Z 违反了该原则,导致数据冗余和潜在的修改异常。


让我们分解一下:

  1. 根据定义,对于函数依赖 X->Y->Z 也是传递的,X<-Y不能成立。
  2. 如果 Y 是键,则 X<-Y 会成立,因此 Y 不能是键。(脚注 1)
  3. 由于 Y 不是键,因此任何给定的 Y 都可以在多行中重复。
  4. Y->Z 意味着拥有相同 Y 的所有行也必须拥有相同的 Z。(脚注 2)
  5. 在几行中重复相同的(Y, Z) 元组不会为系统提供任何有用的信息。这是多余的。

简而言之,由于 Y 不是键且 Y->Z,因此我们违反了 3NF。

冗余导致修改异常(例如,更新一些但不是所有“连接”到同一个 Y 的 Z 本质上会破坏数据,因为您不再知道哪个副本是正确的)。这通常通过将原始表拆分为两个表来解决,一个包含 {X, Y},另一个包含 {Y, Z}。这样,Y 可以是第二个表中的键,Z 不重复。

另一方面,如果 X<-Y 确实成立(即 X->Y->Z 不可传递),那么我们可以保留一个表,其中 X 和 Y 都是键。在这种情况下,不会不必要地重复 Z。

(脚注1)键是一组(最小)属性,它们在功能上确定关系中的所有属性。基本原理:如果 K 是一个键,则不可能有多行具有相同的 K 值,因此任何给定的 K 值总是与每个其他属性的一个值相关联(假设为 1NF)。根据定义(参见脚注 2),“精确关联到一个”与“处于功能依赖中”是一回事。

(脚注2)根据定义,Y->Z 当且仅当每个 Y 值都与一个 Z 值相关联。


例子:

假设每条消息只有一个作者,并且每个作者只有一个主电子邮件,试图在同一个表中表示消息和用户将导致重复电子邮件:

MESSAGE                         USER    EMAIL
-------                         ----    -----
Hello.                          Jon     jon@gmail.com
Hi, how are you?                Rob     rob@gmail.com
Doing fine, thanks for asking.  Jon     jon@gmail.com

(实际上,这些将是MESSAGE_IDs,但让我们在这里保持简单。)

现在,如果 Jon 决定将他的电子邮件更改为“jon2@gmail.com”会发生什么?我们需要更新Jon 的行。如果我们只更新一个,那么我们有以下情况......

MESSAGE                         USER    EMAIL
-------                         ----    -----
Hello.                          Jon     jon2@gmail.com
Hi, how are you?                Rob     rob@gmail.com
Doing fine, thanks for asking.  Jon     jon@gmail.com

...我们不再知道 Jon 的哪一封电子邮件是正确的。我们基本上已经丢失了数据!

这种情况尤其糟糕,因为我们没有可以用来强制 DBMS 为我们执行两个更新的声明性约束。客户端代码会有错误,并且可能在编写时没有过多考虑并发环境中可能发生的复杂交互。

但是,如果您拆分表...

MESSAGE                         USER
-------                         ----
Hello.                          Jon 
Hi, how are you?                Rob 
Doing fine, thanks for asking.  Jon 

USER    EMAIL
----    -----
Jon     jon@gmail.com
Rob     rob@gmail.com

...现在只有一行知道 Jon 的电子邮件,所以不可能有歧义。

顺便说一句,这一切都可以看作是DRY 原则的另一种表达方式。

于 2012-03-31T11:33:47.560 回答
6

如果你的表中有传递依赖,那么它不符合 3NF;所以很有可能你的表中有冗余数据。检查这个以澄清这个概念。

于 2012-03-30T21:10:57.887 回答
3

看看这个链接:

http://en.wikipedia.org/wiki/Transitive_dependency

使用该示例,如果我在一行中更新儒勒·凡尔纳 (Jules Verne) 的国籍,而不是另一行,会发生什么情况?作者的国籍是由作者单独决定的,而不是书和作者的结合。因此,通过示例数据结构,我可能会询问数据库 Jules Verne 的国籍。如果我运行以下 SQL 命令

SELECT TOP 1 author_nationality FROM books WHERE author='Jules Verne'

根据数据库如何选择 TOP 1,我可能会得到不同的答案。

于 2012-03-30T21:11:30.547 回答