173

我读过这句话: 数据取决于键 [1NF]、整个键 [2NF],除了键 [3NF] 什么都没有

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

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

那么为什么有些 3NF 表不在 BCNF 中呢?我的意思是,3NF 引用明确表示“只有键”,这意味着所有属性都仅取决于主键。毕竟,主键是一个候选键,直到它被选为我们的主键。

如果到目前为止我的理解有任何问题,请纠正我并感谢您提供的任何帮助。

4

6 回答 6

171

您的比萨饼可以恰好有三种浇头类型:

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

所以我们点了两个比萨饼并选择以下配料:

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

这是一个8岁的孩子可能理解的解释。这是更技术性的版本。

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

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

因为每个比萨饼必须具有每种浇头类型中的一种,所以我们知道 (Pizza, Topping Type) 是候选键。我们也直观地知道,给定的浇头不能同时属于不同的类型。所以 (Pizza, Topping) 必须是唯一的,因此也是候选键。所以我们有两个重叠的候选键。

我展示了一个异常,我们将 mozarella 标记为错误的浇头类型。我们知道这是错误的,但导致错误的规则是依赖关系Topping -> Topping Type,它不是该表的 BCNF 的有效依赖关系。它依赖于整个候选键以外的东西。

所以为了解决这个问题,我们从 Pizzas 表中取出 Topping Type 并使其成为 Toppings 表中的非键属性。

于 2011-12-08T22:50:10.370 回答
91

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

最好使用Zaniolo对 3NF 的定义来解释这一点,它相当于 Codd 的:

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

(a) X 是 R 的超键,

(b) A 是 R 的关键属性

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

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

(a) X 是 R 的超级键

因此,BCNF 更加严格。

差异是如此微妙,以至于许多人非正式地描述为 3NF 实际上是 BCNF。例如,您在此处声明 3NF 的意思是“数据取决于密钥 [s]...,而只有密钥 [s]”,但这实际上是 BCNF 而不是 3NF 的非正式描述。3NF 可以更准确地描述为“非密钥数据取决于密钥......而且只有密钥”。

你还说:

3NF 引用明确表示“只有键”,这意味着所有属性都仅取决于主键。

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

于 2011-12-09T16:05:33.787 回答
33

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. 超级键是关系变量的一组属性,它认为在分配给该变量的所有关系中,没有两个不同的元组(行)具有相同的属性值。同样地,超级键也可以被定义为关系模式的一组属性,模式的所有属性在功能上都依赖于这些属性。(超级键始终包含一个候选键/候选键始终是超级键的子集。您可以在关系中添加任何属性以获得其中一个超级键。)

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

不在 BCNF 中的表/关系会出现异常,例如另一个用户在比萨示例中提到的更新异常。很遗憾,

  • BNCF不能总是获得,而
  • 3NF总是可以得到的。

3NF 与 BCNF 示例

目前可以在 Wikipedia 上的“ 3NF table not meet BCNF (Boyce–Codd normal form) ”中找到差异的示例,其中下表符合 3NF 但不符合 BCNF,因为“Tennis Court”(部分关键/主要属性)取决于关于“速率类型”(不是超键的部分键/主属性),这是一个依赖关系,我们可以通过询问数据库的客户端网球俱乐部来确定:

今天的网球场预订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”依赖于超键以外的其他东西。相反,它依赖于部分键/主要属性“速率类型”。这意味着如果我们升级球场,用户必须手动更改费率类型,或者如果想要应用费率更改,用户必须手动更改球场。

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

(从技术上讲,我们不能保证不会违反“Rate Type”->“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

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

(从技术上讲,我们可以保证不会违反函数依赖“Rate Type”->“Court”。)

于 2015-10-27T22:13:32.207 回答
7

所有好的答案。用简单的语言说[BCNF]没有部分键可以依赖于键。

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

于 2013-02-13T17:38:03.500 回答
5

'<strong>smartnut007'、'<strong>Bill Karwin' 和 '<strong>sqlvogel' 的回答非常出色。然而,让我提出一个有趣的观点。

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

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

非素数可以依赖或不依赖

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

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

素数之间的依赖关系如何?

现在你看,我们不是通过第二个或第三个 NF 来解决素数之间的依赖关系。此外,这种依赖(如果有的话)是不可取的,因此我们有一个单一的规则来解决这个问题。这是BCNF

参考Bill Karwin在此处的帖子中的示例,您会注意到 '<em>Topping' 和 '<em>Topping Type' 都是主键并具有依赖关系。如果它们是具有依赖性的非素数,那么 3NF 就会发挥作用。

笔记:

BCNF 的定义非常通用,没有区分素数和非素数的属性。然而,上述思维方式有助于理解即使在第 2 次和第 3 次 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

于 2016-10-03T11:03:43.387 回答
4

这是一个很老的问题,答案很有价值,但在找到一个显示 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) 对于每个属性Teacher, Date, Room,我们每行只有一个值。(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取决于Teacher,Room必须是Teacher(不是这种情况)的子集或Teacher必须是超级键(我的日记中不是这种情况,但是拆分表时就是这种情况)。

总结一下:BNCF 比 3NF 更严格,但在我看来更容易掌握:

  • 在大多数情况下,BCNF 与 3NF 相同;
  • 在其他情况下,BCNF 就是您认为/希望的 3NF。
于 2018-12-17T15:50:29.530 回答