3NF和BCNF的简单区别(必须能够向8岁儿童解释)


157

我已经读过这句话: 数据取决于键[1NF],整个键[2NF],而仅取决于键[3NF]

但是,我很难理解所谓的3.5NF或BCNF。这是我的理解:

  • BCNF比3NF严格
  • 表格中任何FD的左侧必须是超级键(或至少是候选键)

那么,为什么有些3NF表不在BCNF中?我的意思是,3NF引号明确表示“除了密钥”,这意味着所有属性仅取决于主键。毕竟,主键是候选键,直到被选为我们的主键为止。

到目前为止,如果对我的理解有任何不妥之处,请纠正我,并感谢您能提供的任何帮助。


这种感觉很奇怪,以至于只有出版的教科书才能提供对概念的简洁,准确的描述。如果您看一下这个(确实是很古老的)问题的答案,您会发现没有一个被高度评价的问题是模糊或不精确的。拥有代数定义不是问题,而是通过实际示例了解概念。至于我原来的问题中的报价,谷歌“所以帮助我科德”找到报价的来源。没有什么含糊的。
Arnab Datta

1
您认为非教科书来源从哪里获得信息呢?也有很多糟糕的教科书,但是教科书是由多位具有学徒制的人审阅的,而且比其他人对教科书的解释更废话。不知情和不知情的人所给予的高评价不会使事情变得正确。我把那条评论放在这里,供那些提出您问题的人使用。“只有钥匙”这句话没什么用。正确的定义当然是问题所在,因为没有一个人就不可能“理解概念”。
philipxy

Answers:


162

您的披萨可以完全具有三种浇头类型:

  • 一种奶酪
  • 一种肉
  • 一种蔬菜

因此,我们订购了两个比萨饼,然后选择以下浇头:

Pizza    Topping     Topping Type
-------- ----------  -------------
1        mozzarella  cheese
1        pepperoni   meat
1        olives      vegetable
2        mozzarella  meat
2        sausage     cheese
2        peppers     vegetable

等一下,马苏里拉奶酪既不能兼具奶酪又可以兼得肉!香肠不是奶酪!

我们需要防止此类错误,以使马苏里拉奶酪永远成为奶酪。为此,我们应该使用一个单独的表,因此我们只在一个地方写下该事实。

Pizza    Topping
-------- ----------
1        mozzarella
1        pepperoni
1        olives
2        mozzarella 
2        sausage
2        peppers

Topping     Topping Type
----------  -------------
mozzarella  cheese
pepperoni   meat
olives      vegetable
sausage     meat
peppers     vegetable

那是一个八岁的孩子可能理解的解释。这是更多技术版本。

仅当存在多个重叠的候选键时,BCNF与3NF的行为不同。

原因是X -> Y如果Y是的子集,则功能依赖项当然是正确的X。因此,在只有一个候选键并且在3NF中的任何表中,它已经在BCNF中,因为除了该键之外,没有任何列在功能上依赖于任何内容的列(键或非键)。

因为每个披萨必须完全具有每种浇头类型之一,所以我们知道(Pizza,浇头类型)是候选键。我们还凭直觉知道给定的浇头不能同时属于不同的类型。因此(Pizza,Topping)必须是唯一的,因此也是候选关键字。因此,我们有两个重叠的候选键。

我显示了一个异常,我们将mozarella标记为错误的浇头类型。我们知道这是错误的,但是使它出错的规则是依赖性Topping -> Topping Type,该依赖性对于此表的BCNF无效。除了整个候选键之外,它还依赖于其他东西。

因此,要解决此问题,我们从“披萨”表中删除“浇头类型”,并使其成为“浇头”表中的非关键属性。


3
“这是依赖于整个候选密钥以外的东西。” -谢谢
gnsb

12
“所以在任何只有一个候选键且在3NF中的表中” –不太正确。您提供的示例确实满足此条件。但是,它不是3NF示例,因为它不是2NF。密钥(1NF),整个密钥(2NF),除了密钥(3NF)外什么也没有。键是(Pizza,Topping),并且列ToppingType取决于键,除了键外什么都没有,但它不依赖于整个键。因此它不是2NF,因此不是3NF或BCNF。是1NF。将其设置为2NF将绕过您试图说明的问题。
丹尼尔·巴巴拉斯

4
@DanielBarbalace,此表的要点是它具有此表的备用候选键:(Pizza,ToppingType)。由于ToppingType是该候选密钥的子集,因此满足2NF。
Bill Karwin '17

6
抱歉,我不得不投票。您显示的示例不在3NF中。要了解BCNF的目的,我必须看到一个示例,它位于3NF中,而不是i BCNF中。现在,我看不到BCNF的目的。
Spero

5
为什么在2NF中未对此进行处理?在我看来,原始表的主键是Pizza + Topping,并且Topping Type依赖于Topping,所以不是在2NF阶段应注意的部分依赖关系吗?
GreenPenguin

91

微妙的区别是3NF区分了关键属性和非关键属性(也称为非主要属性),而BCNF则没有。

最好使用Zaniolo对3NF 的定义来解释,该定义等同于Codd的定义:

对于每个至少满足以下条件之一的非平凡FD(X-> A),关系R在3NF iff中:

(a)X是R的超键,

(b)A是R的关键属性

BCNF要求(a),但不将(b)视为自己的特殊情况。换句话说,BCNF要求每个非平凡的行列式都是一个超键,即使其相关属性恰好是键的一部分。

对于满足R的每个非平凡FD(X-> A),BCNF中的关系R为满足以下条件:

(a)X是R的超键

因此,BCNF更加严格。

这种差异是如此微妙,以至于许多人非正式地将3NF称为BCNF。例如,您在此处说过3NF的意思是“数据取决于密钥……而仅取决于密钥”,但这实际上是对BCNF的非正式描述,而不是3NF。3NF可以更准确地描述为“ 非密钥数据取决于密钥……而仅取决于密钥”。

您还说过:

3NF引号明确表示“仅键”,意思是所有属性仅取决于主键。

这太简单了。3NF和BCNF以及所有范式都与所有候选键和/或超键有关,而不仅仅是一个“主”键。


7
哇。Zaniolo教授实际上是在教我的课程(CS 143,加州大学洛杉矶分校),我在准备期末考试时偶然发现了这个答案。很高兴看到我教授的名字,并感谢您的详细回答!
DV。

您能否举一个在3NF中而不在BCNF中的关系的例子?这让我很难想象...
Leo

10
R {A,B,C},其中{A,B}是键。给定依赖性C-> B,R满足3NF的要求,但不满足BCNF的要求。
nvogel 2013年

2
密钥表示候选密钥。密钥属性是指作为候选密钥的一部分的属性,又称主要属性
nvogel '16

3
如果属性是任何候选键的一部分,则该属性为质数;非主键(如果它不是任何候选键的一部分)。
nvogel '16

26

BCNF和3NF之间的区别

使用BCNF定义

当且仅当对于它的每个依赖项X→Y,至少满足以下条件之一

  • X→Y是一个琐碎的函数依存关系(Y⊆X),或者
  • X是架构R的超级键

和3NF定义

对于且仅当针对其每个功能依赖项X→A时,至少满足以下条件之一:

  • X包含A(即X→A是琐碎的函数依赖性),或者
  • X是超键,或
  • AX的每个元素(A和X之间的设置差)都是素数属性(即AX中的每个属性都包含在某个候选键中)

简单来说,我们看到以下差异:

  • 在BCNF中:每个部分键(素数属性)只能依赖于一个超键,

  • 在3NF中:部分键(素数属性)也可以依赖于不是超键的属性(即另一个部分键/素数属性,甚至是非素数属性)。

哪里

  1. 一个主属性是一个候选键找到一个属性,
  2. 一个候选键是该关系的最小的超密钥,并
  3. 超密钥是一组的关系可变的属性的用于其保持在分配给该变量的所有关系,不存在两个不同的元组具有在此set.Equivalently一个超密钥对的属性相同的值(行)也可以被定义为关系模式的一组属性,该模式的所有属性在功能上都依赖于该关系模式。(一个超键始终包含一个候选键/一个候选键始终是一个超键的子集。您可以在关系中添加任何属性以获得一个超键。)

也就是说,候选键的部分子集(除完整集外的任何非平凡子集)在功能上都不能依赖于超级键以外的任何东西。

不在BCNF中的表/关系会受到异常的影响,例如另一个用户在披萨示例中提到的更新异常。不幸,

  • BNCF 不能总是获得,而
  • 始终可以获得3NF

3NF与BCNF示例

当前可以在Wikipedia 上的“ 3NF表不满足BCNF(Boyce–Codd正常形式) ”中找到差异的示例,该表满足3NF但不满足BCNF,因为“网球场”(部分键/素数属性)取决于在“费率类型”(不是超级键的部分键/素数属性)上,这是一种依赖关系,我们可以通过询问数据库的客户网球俱乐部来确定:

今日的网球场预订3NF,不是 BCNF

Court   Start Time  End Time    Rate Type
------- ----------  --------    ---------
1       09:30       10:30       SAVER
1       11:00       12:00       SAVER
1       14:00       15:30       STANDARD
2       10:00       11:30       PREMIUM-B
2       11:30       13:30       PREMIUM-B
2       15:00       16:30       PREMIUM-A

该表的超键是:

S1 = {Court, Start Time}
S2 = {Court, End Time}
S3 = {Rate Type, Start Time}
S4 = {Rate Type, End Time}
S5 = {Court, Start Time, End Time}
S6 = {Rate Type, Start Time, End Time}
S7 = {Court, Rate Type, Start Time}
S8 = {Court, Rate Type, End Time}
ST = {Court, Rate Type, Start Time, End Time}, the trivial superkey

3NF问题:部分键/主键属性“ Court”依赖于除超级键以外的其他东西。相反,它取决于部分键/主键属性“费率类型”。这意味着,如果我们升级法院,则用户必须手动更改费率类型,如果要应用费率更改,则必须手动更改法院。

  • 但是,如果用户升级球场但不记得要提高费率怎么办?或者如果将错误的费率类型应用于法院怎么办?

(用技术术语来说,我们不能保证不会违反“费率类型”->“法院”功能的依赖。)

BCNF解决方案:如果要将上表放在BCNF中,我们可以将给定的关系/表分解为以下两个关系/表(假设我们知道费率类型仅取决于法院和会员资格,我们可以通过查询我们数据库的客户(网球俱乐部的所有者)发现:

费率类型BCNF和较弱的3NF,这是BCNF隐含的)

Rate Type   Court   Member Flag
---------   -----   -----------
SAVER       1       Yes
STANDARD    1       No
PREMIUM-A   2       Yes
PREMIUM-B   2       No

当今的网球场预订量BCNF和较弱的3NF,这是BCNF暗示的)

Member Flag     Court     Start Time   End Time
-----------     -----     ----------   --------
Yes             1         09:30        10:30
Yes             1         11:00        12:00
No              1         14:00        15:30
No              2         10:00        11:30
No              2         11:30        13:30
Yes             2         15:00        16:30

解决的问题:现在,如果我们升级法院,我们可以保证费率类型将反映这种变化,并且我们不会为法院收取错误的价格。

(从技术上讲,我们可以保证不会违反功能依赖性“费率类型”->“法院”。)


6

所有好的答案。用简单语言[BCNF]来表示,部分键不能依赖于键。

即,候选键的部分子集(即除完整集外的任何非平凡子集)在功能上都不能依赖于某个候选键。


2
为什么不?假设存在一个关系R(A,B,C,D,E),并且(A,B)和(C,D)是候选键。然后AB-> D。由于AB是R的超键,所以R应该在BCNF中,对吗?(只是一个问题,试图理解这一点。)
peteykun 2014年

3

smartnut007 ”,“ Bill Karwin ”和“ sqlvogel ” 的回答非常好。但是,让我提出一个有趣的观点。

好吧,我们有主键和非主键。

当我们关注非素数如何依赖素数时,我们看到两种情况:

非素数可以是依赖项,也可以不是

  • 依赖时:我们看到它们必须依赖完整的候选键。这是2NF
  • 不依赖时:可以没有依赖或传递依赖

    • 甚至没有传递依赖性:不确定什么规范化理论可以解决这个问题。
    • 传递依赖时:被认为是不可取的。这是3NF

素数之间的依赖性如何?

现在您知道,我们没有解决第二或第三NF 素数之间的依赖关系。此外,这种依赖性(如果有的话)是不希望的,因此我们有一条规则可以解决这个问题。这是BCNF

参照Bill Karwin在此处发布的示例,您会注意到' Topping '和' Topping Type '都是主键并具有依赖性。如果它们不是具有依赖性的素数,那么3NF就可以加入。

注意:

BCNF的定义非常通用,并且没有区分素数和非素数的属性。然而,上述思维方式有助于理解即使在第二和第三次NF之后仍会渗入一些异常。

高级主题:将通用BCNF映射到2NF和3NF

既然我们知道BCNF提供了一个通用定义,而没有引用任何素数/非素数属性,那么让我们看看BCNF和2/3 NF是如何关联的。

首先,BCNF要求(除一般情况外)对于每个功能依赖项X -> Y(FD),X应该是超键。如果仅考虑任何FD,那么我们有三种情况-(1)X和Y均为非素数,(2)素数和(3)X素数和Y非素数,丢弃(无意义的)情况X非-素数和Y素数。

对于情况(1),由3NF负责。

对于情况(3),由2NF负责。

对于情况(2),我们发现使用BCNF


3

这是一个古老的问题,提供了有价值的答案,但直到发现一个真实的例子来说明3NF的问题,我还是有些困惑。也许不适合8岁的孩子,但希望对您有所帮助。

明天我将在每个季度的家长/老师会议中与长女的老师见面。这是我的日记的样子(名称和房间已更改):

Teacher   | Date             | Room
----------|------------------|-----
Mr Smith  | 2018-12-18 18:15 | A12 
Mr Jones  | 2018-12-18 18:30 | B10 
Ms Doe    | 2018-12-18 18:45 | C21 
Ms Rogers | 2018-12-18 19:00 | A08 

每个房间只有一位老师,他们永远都不会动。如果你看看,你会发现:(1)每个属性TeacherDateRoom,我们有每行只有一个值。(2)超键是:(Teacher, Date, Room)(Teacher, Date)并且(Date, Room)和候选键显然(Teacher, Date)(Date, Room)

(Teacher, Room) 不是超级键,因为我将在下个季度完成表格,并且我可能会有这样的一行(史密斯先生没有动!):

Teacher  | Date             | Room
---------|------------------| ----
Mr Smith | 2019-03-19 18:15 | A12

我们可以得出什么结论?(1)是非正式但正确的1NF公式。从(2)中我们看到没有“非主要属性”:免费提供2NF和3NF。

我的日记是3NF。好!不。不是真的,因为没有数据建模者会在数据库模式中接受此设置。该Room属性取决于该Teacher属性(再次:教师不要移动!),但是架构不能反映这一事实。一个理智的数据建模者会做什么?将表一分为二:

Teacher   | Date
----------|-----------------
Mr Smith  | 2018-12-18 18:15
Mr Jones  | 2018-12-18 18:30
Ms Doe    | 2018-12-18 18:45
Ms Rogers | 2018-12-18 19:00

Teacher   | Room
----------|-----
Mr Smith  | A12
Mr Jones  | B10
Ms Doe    | C21
Ms Rogers | A08

但是3NF不能处理主要属性依赖性。问题是:在某些情况下,符合3NF标准不足以确保合理的表架构设计。

使用BCNF,您无需担心2NF和3NF规则中的属性是否是质数属性。对于每个非平凡的依赖关系(子集显然由其超集确定),行列式是一个完整的超键。换句话说,除了一个完整的超级键(不包括琐碎的FD)之外,没有什么决定。(有关正式定义,请参见其他答案)。

一旦Room依靠TeacherRoom必须是Teacher(不是这种情况的)子集,或者Teacher必须是一个超级键(我的日记中不是这种情况,但是拆分表时就是这种情况)。

总结:BNCF比3NF更严格,但我认为更容易掌握:

  • 在大多数情况下,BCNF与3NF相同;
  • 在其他情况下,BCNF是您认为/希望的3NF。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.