传递依赖关系有什么问题



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

我并不是在争论这个事实,只是急于了解它们会引发什么样的问题。

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

来自维基百科:

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

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

-------------------------------------------------------------------
|  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,你可以很容易地得到它的Instructor,所以Course->Instructor
  • 如果你有一个Instructor,你就不能得到他的Course,因为他可能在教不同的课程
  • 如果你有一个Instructor,你可以很容易地得到他的Phone,所以Instructor->Phone

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

现在针对问题:

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

表示3NF的一种方法是:

所有属性都应该依赖于键、整个键,只依赖于键

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


让我们来分解一下:

  1. 根据定义,对于函数依赖X->Y->Z也是传递性,X&lt-Y必须而不是保持
  2. 如果Y是键,则X&lt-Y会保持,所以Y不能是一把钥匙(脚注1)
  3. 由于Y不是键,任何给定的Y都可以在多行中重复
  4. Y->Z意味着持有相同Y的所有行也必须持有相同的Z。(FOOTNOTE2)
  5. 在几行中重复相同的(Y,Z)元组不会为系统提供任何有用的信息。它是多余的

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

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

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

(FOOTNOTE1)键是一组(最小)属性,在功能上决定关系中的所有属性。理由:如果K是一个键,则不可能有多行具有相同的K值,因此任何给定的K值总是与每个其他属性的一个值精确关联(假设1NF)。根据定义(参见FOOTNOTE2),"与精确的一个相关联"与"处于功能依赖关系中"是一样的

(FOOTNOTE2)根据定义,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_ID,但让我们在这里保持简单。)

现在,如果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

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

这种情况尤其糟糕,因为没有声明性约束可以用来强迫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原理的另一种表达。

如果表中存在可传递依赖项,则它不符合3NF;因此,表中很有可能存在冗余数据。检查此项以澄清此概念。

看看这个链接:

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

举个例子,如果我在一排更新儒勒·凡尔纳的国籍,而在另一排不更新,会发生什么?作者的国籍是由作者单独决定的,而不是书和作者的结合。因此,通过示例数据结构,我可以向数据库询问儒勒·凡尔纳的国籍。如果我运行以下SQL命令

从书籍中选择排名前1的作者WHERE author="儒勒·凡尔纳"

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

最新更新