3NF 和 BCNF 之间的区别在于简单的术语(必须能够向一个8岁的孩子解释)

我读过这句话: 数据依赖于键[1NF ] ,整个键[2NF ] ,只有键[3NF ]

然而,我在理解3.5 NF 或者 BCNF 时遇到了困难。以下是我的理解:

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

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

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

207143 次浏览

你的比萨饼可以有三种配料:

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

所以我们点了两个披萨,然后选择下面的配料:

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

原因是,如果 YX的子集,那么函数依赖 X -> Y当然是正确的。所以在任何只有一个候选键并且使用3NF 的表中,它已经在 BCNF 中了,因为在功能上除了该键之外,没有任何列(键或非键)依赖于其他任何东西。

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

我发现了一个异常现象,我们把莫扎里拉奶酪标记为错误的配料类型。我们知道这是错误的,但是使它错误的规则是依赖项 Topping -> Topping Type,它不是这个表的 BCNF 的有效依赖项。它依赖于某种东西,而不是一个完整的候选密钥。

为了解决这个问题,我们将 Topping Type 从 Pizza 表中取出,并将其作为 Toppings 表中的非键属性。

微妙的区别在于3NF 区分了键属性和非键属性(也称为 非素数属性) ,而 BCNF 没有区分。

这是最好的解释使用 Zaniolo 的定义的3NF,这相当于 Codd 的:

满足每个非平凡 FD (X-> A)的一个关系 R 是3NF 的充要条件下的充要条件 至少符合下列其中一项条件:

(a) X 是 R,或者的超密钥

(b) A 是 R 的关键属性

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

对于满足的每个非平凡 FD (X-> A) ,关系 R 在 BCNF 当中充分满足 R 表示下列条件为真:

(a) X 是 R 的超密钥

因此 BCNF 更加严格。

这种差异是如此微妙,以至于许多人非正式地描述为3NF 的实际上是 BCNF。例如,您在这里指出,3NF 意味着“数据取决于键[ s ] ... ... 除了键[ s ]什么都没有”,但这实际上是对 BCNF 的非正式描述,而不是3NF。3NF 可以更准确地描述为“ 非密码匙资料非密码匙资料取决于键... ... 除了键什么也不是”。

你还说:

3NF 引用明确地说“除了钥匙什么都没有”意思是所有 属性仅依赖于主键。

你过于简单化了。3NF 和 BCNF 以及所有的标准表单都与 所有候选键和/或超键有关,而不仅仅是一个“主键”。

都是好答案。用简单的语言来说[ BCNF ]没有部分密钥可以依赖于一个密钥。

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

BCNF 与3NF 的差异

使用 BCNF 定义

当且仅当对于它的每一个依赖项 X → Y,下列条件中至少有一个保持 :

  • X → Y 是一个平凡的函数依赖关系(Y something X) ,或者
  • X 是模式 R 的超键

和3NF 定义

当且仅当对于它的每个函数依赖项 X → A,至少有以下一个条件成立:

  • X 包含 A (即 X → A 是平凡的函数依赖) ,或者
  • X 是超级密钥,或者
  • A-X 中的每个元素,即 A 和 X 之间的集合差异,都是一个主属性(也就是说,A-X 中的每个属性都包含在某个候选关键字中)

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

  • 在 BCNF 中: 每个部分密钥(质属性)可以 只有依赖于一个超级密钥,

然而呢

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

在哪里

  1. 质属性是在候选键中找到的属性,并且
  2. 备用钥匙是该关系的最小超键,并且
  3. 超级密钥是关系变量的一组属性,它认为在分配给该变量的所有关系中,没有两个不同的元组(行)具有相同的属性值。同样,超级密钥也可以定义为关系模式的一组属性,该模式的所有属性在功能上都依赖于这些属性。(超级密钥总是包含一个候选密钥/候选密钥总是超级密钥的子集。您可以在关系中添加任何属性以获得其中一个超键。)

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

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

  • BNCF 不能总是获得 ,而
  • 获得3NF 永远都可以

3NF 与 BCNF 示例

这种差异的一个例子可以在维基百科的“ 3NF 表不符合 BCNF (Boyce-Codd 标准格式)”中找到,下面的表符合3NF,但不符合 BCNF,因为“网球场”(一个部分键/质属性)取决于“率类型”(一个部分键/质属性,是 没有一个超级键) ,这是一个依赖关系,我们可以通过询问数据库的客户,网球俱乐部来确定:

今日网球场预订情况(3NF,< em > not 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”。这意味着用户必须手动更改费率类型,如果我们升级法院,或手动更改法院,如果想要应用费率变化。

  • 但是,如果用户升级法院,但不记得增加费率?或者,如果错误的利率类型适用于法院?

(从技术角度来说,我们不能保证“ 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”不会被违反。)

小聪明007”、“ Bill Karwin”和“ 乌龟”的答案都非常好,但是让我用一个有趣的角度来看待它。

我们有质键和非质键。

当我们关注非素数如何依赖素数时,我们看到两个例子:

非素数可以是依赖的,也可以不是强的。

  • 当依赖于: 时,我们看到它们必须依赖于一个完整的候选键。
  • 当不依赖时: 可以是非依赖或传递依赖

    • 甚至连传递依赖也没有: 不确定规范化理论解决了这个问题。
    • 当传递依赖时: 它被认为是不受欢迎的,这是 3NF

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

现在您可以看到,我们并没有通过第2或第3 NF 来处理 质数之间的依赖关系。 进一步这样的依赖,如果有的话,是不可取的,因此我们有一个单一的规则来解决这个问题。

参考 Bill Karwin的文章中的例子,你会注意到‘ 打顶’和‘ 浇头类型’都是质键,并且有依赖关系。如果他们是有依赖性的非质数,那么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 的使用

这是一个有着宝贵答案的老问题,但是我仍然有点困惑,直到我找到了一个真实的例子来说明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)是一个非正式但正确的表述。从(2)我们可以看到没有“非质属性”: 2NF 和3NF 是免费提供的。

我的日记是3NF。很好!没有。实际上并非如此,因为没有数据建模师会在 DB 模式中接受这一点。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 不处理主属性依赖关系

使用 BCNF,您不会关心属性是否是2NF 和3NF 规则中的主属性。对于每个非平凡的依赖项(子集显然是由它们的超集决定的) ,行列式是一个完整的超键。换句话说,除了一个完整的超级密钥之外,没有什么是由其他东西决定的(不包括小型 FD)。(有关正式定义,请参阅其他答案)。

一旦 Room依赖于 Teacher,那么 Room必须是 Teacher的子集(事实并非如此) ,或者 Teacher必须是一个超级键(我的日记中并非如此,但当你拆分表时就是这种情况)。

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

  • 在大多数情况下,BCNF 与3NF 相同;
  • 在其他情况下,BCNF 就是您所认为的/希望的3NF。