我的数据库设计中有一些传递依赖项。我的上级告诉我,这些可能会导致错误。我发现很难找到能够告诉我这些依赖项将如何导致错误的资源。它们会带来什么样的问题?
我不是在争论这个事实,只是渴望了解它们会引起什么样的问题。
编辑以获取更多详细信息:
来自维基百科:
传递依赖
传递依赖是一种间接的函数依赖,其中 X→Z 仅凭借 X→Y 和 Y→Z。
我的数据库设计中有一些传递依赖项。我的上级告诉我,这些可能会导致错误。我发现很难找到能够告诉我这些依赖项将如何导致错误的资源。它们会带来什么样的问题?
我不是在争论这个事实,只是渴望了解它们会引起什么样的问题。
编辑以获取更多详细信息:
来自维基百科:
传递依赖
传递依赖是一种间接的函数依赖,其中 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
so Course->Instructor
。Instructor
你不能得到他的Course
,因为他可能正在教不同的课程。Instructor
你可以很容易地得到他的Phone
so Instructor->Phone
。这意味着如果你有一个Course
then 你可以得到Instructor Phone
which 意味着 Course->Instructor Phone
(即传递依赖)
现在解决问题:
French
和English
课程,那么您也将删除他们的讲师John Doe
,并且他的电话号码将永远丢失。Instructor
您的数据库添加一个新的Course
,或者您可以将数据复制到一个Instructors table
更糟糕的地方。John Doe
更改了他的电话号码,那么您将不得不使用新信息更新他教授的所有课程,这很容易出错。Birth Date
字段。Courses
这听起来合乎逻辑吗?为什么首先要在课程表中保留讲师信息?表达 3NF 的一种方法是:
所有属性都应该依赖于密钥、整个密钥,而只有密钥。
传递依赖 X->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_ID
s,但让我们在这里保持简单。)
现在,如果 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 原则的另一种表达方式。
如果你的表中有传递依赖,那么它不符合 3NF;所以很有可能你的表中有冗余数据。检查这个以澄清这个概念。
看看这个链接:
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,我可能会得到不同的答案。