3NF和BCNF之间的区别(必须能够解释为一个8岁)
我读过报价: 数据取决于密钥[1NF],整个密钥[2NF],只有密钥[3NF] 。
但是,我无法理解3.5NF或BCNF。 这是我明白的:
- BCNF比3NF严格
- 表格中任何FD的左侧必须是超级键(或至less一个候选键)
那么为什么有些3NF表格不在BCNF呢? 我的意思是,3NF的引用明确地说“只有关键”,这意味着所有属性完全依赖主键。 主键毕竟是一个候选键,直到被选为我们的主键。
如果到目前为止我的理解有任何问题,请纠正我,并感谢您提供的任何帮助。
你的比萨可以有三种顶级types:
- 一种types的奶酪
- 一种肉类
- 一种蔬菜
所以我们点了两个比萨饼,然后select下面的配料:
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的行为不同。
原因是,如果Y
是X
一个子集,那么函数依赖X -> Y
当然是真的。 因此,在任何只有一个候选键并且在3NF中的表中,它已经在BCNF中,因为除了该键以外,没有列(键或非键)在function上依赖于任何其他键。
因为每个比萨必须有一个顶部types,我们知道(比萨,顶部types)是一个候选关键。 我们也直观地知道,给定的顶部不能同时属于不同的types。 所以(披萨,顶部)必须是唯一的,因此也是候选关键。 所以我们有两个重叠的候选键。
我发现一个exception,我们把mozarella标记为错误的打顶types。 我们知道这是错误的,但是造成错误的规则是依赖Topping -> Topping Type
,它不是BCNF对这个表的有效依赖。 这是除了整个候选键之外的其他东西的依赖。
所以要解决这个问题,我们把Topping Type从Pizzas表中取出来,并把它作为Toppings表中的非关键属性。
细微的区别是,3NF区分了键和非键属性(也称为非素数属性),而BCNF则没有。
这是最好的解释使用Zaniolo的 3NF,这相当于Codd的定义:
如果对于R所满足的每个非平凡FD(X-> A)满足下列条件中的至less一个为真,则关系R在3NF中:
(a)X是R的一个超级键, 或者
(b)A是R的关键属性
BCNF要求(a)但不把(b)视为自己的特例。 换句话说,BCNF要求每一个非平凡的行列式都是一个超级键,即使它的依赖属性恰好是键的一部分。
一个关系R在BCNF iff中,对于由R满足的每个非平凡FD(X-> A),下列条件成立:
(a)X是R的超级键
BCNF因此更为严格。
差别非常微妙,许多人非正式地描述为3NF实际上是BCNF。 例如,你在这里指出,3NF的意思是“数据取决于关键[…]而不是关键[s]”,但这实际上是BCNF的非正式描述,而不是3NF。 3NF可以更准确地描述为“ 非关键数据取决于关键…而只是关键”。
你还说:
3NF的引用明确地说“只有关键”意味着所有的属性完全依赖于主键。
这太简单了。 3NF和BCNF以及所有正常forms都涉及所有候选键和/或超键,而不仅仅是一个“主”键。
BCNF和3NF的区别
使用BCNF定义
当且仅当对于其每个依赖X→Y,至less满足下列条件之一 :
- X→Y是一个平凡的函数依赖(Y⊆X),并且
- X是模式R的超级键
和3NF的定义
当且仅当对于其每个函数依赖关系X→A,至less满足下列条件之一:
- X包含A(即X→A是平凡的函数依赖),或者
- X是一个超级键,或者
- AX的每个元素(A和X之间的集合差异)是一个主要属性(即AX中的每个属性都包含在某个候选键中)
我们看到以下差别,简单来说:
- 在BCNF中 :每个部分键(prime属性) 只能依赖一个超级键,
而
- 在3NF中 :部分关键字(主属性)也可以取决于不是超级关键字的属性(即另一个部分关键字/主属性或甚至非主属性)。
哪里
- 一个主要属性是一个在候选键中find的属性,
- 候选键是这个关系的最小超级键,
- superkey是一个关系variables的一组属性,它认为在分配给该variables的所有关系中,没有两个不同的元组(行)具有相同的值,这个集合中的属性是相同的。相同的,超级键也可以被定义为关系模式的一组属性,模式的所有属性在function上依赖于该属性。 (一个超级键总是包含一个候选键/一个候选键总是一个超级键的子集,你可以在关系中添加任何一个属性来获得一个超级键。)
也就是说,候选关键字的任何部分子集(除完整集合外的任何非平凡子集)都可以在function上依赖于超级键之外的任何其他关键字。
不在BCNF中的表/关系会受到exception情况的影响,例如其他用户在比萨示例中提到的更新exception。 不幸,
- BNCF 不能总是获得 ,而
- 3NF 总是可以获得的 。
3NF与BCNF的例子
目前可以在维基百科上的“ 3NF table not meets BCNF(Boyce-Codd normal form) ”中find差异的例子,其中下表符合3NF,但不符合BCNF,因为“网球场”(部分密钥/素数属性)取决于在“费率types”(一个不是超级密钥的部分密钥/素数属性)上,这是一个依赖关系,我们可以通过向数据库的客户询问网球俱乐部来确定:
今天的网球场预定 ( 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”依赖于超级键之外的其他值。 而是取决于部分密钥/素数属性“费率types”。 这意味着,如果我们升级法院,用户必须手动更改费率types,或者如果想要应用费率变更,请手动更改法院。
- 但是,如果用户升级法院但不记得提高费率呢? 或者如果错误的费率types适用于法庭呢?
(从技术angular度来说,我们不能保证“费率types” – >“法庭”function依赖不会被侵犯。)
BCNF的解决scheme :如果我们想把上面的表格放在BCNF中,我们可以将给定的关系/表格分解成以下两个关系/表格(假设我们知道费率types仅依赖于法院和成员身份,我们可以通过询问我们的数据库的客户,网球俱乐部的业主来发现):
费率types ( BCNF和BCNF隐含的较弱的3NF)
Rate Type Court Member Flag --------- ----- ----------- SAVER 1 Yes STANDARD 1 No PREMIUM-A 2 Yes PREMIUM-B 2 No
今天的网球场预定 ( BCNF和BCNF暗示的较弱的3NF)
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
解决问题 :现在如果我们升级法庭,我们可以保证费率types将反映这种变化,我们不能向法院收取错误的价格。
(在技术上,我们可以保证function依赖“费率types” – >“法院”不会被违反。)
所有好的答案。 用简单的语言[BCNF]没有部分的密钥可以依靠一个密钥。
即,候选密钥的没有部分子集(即除全集以外的任何非平凡子集)可以在function上依赖于某个候选密钥。
“ smartnut007 ”,“ Bill Karwin ”和“ sqlvogel ”的答案非常好。 但是,让我对它有一个有趣的看法。
那么,我们有主要和非主要密钥。
当我们关注非素数如何依赖素数时,我们看到两种情况:
非素数可以依赖或不依赖 。
- 当依赖时:我们看到他们必须依靠一个完整的候选键。 这是2NF 。
-
不依赖时:可以不存在依赖关系或传递依赖关系
- 甚至没有传递依赖:不知道什么规范化理论解决这个问题。
- 当传递依赖:这被认为是不受欢迎的。 这是3NF 。
素数之间的依赖关系如何?
现在你看,我们并没有解决第二或第三NF的素数之间的依赖关系。 进一步的这种依赖,如果有的话,是不可取的,因此我们有一个单一的规则来解决这个问题。 这是BCNF 。
参考比尔·卡尔文 ( Bill Karwin )在这里的post,你会注意到' Topping '和' Topping Type '都是主键,并且具有依赖性。 如果他们是非素质的依赖,那么3NF就已经踢了。
注意:
BCNF的定义是非常通用的,没有区分素数和非素数之间的属性。 然而,上述思维方式有助于理解甚至在第二次和第三次核反应后如何渗透一些exception。
高级主题:将通用BCNF映射到2NF&3NF
现在我们知道BCNF提供了一个通用的定义,而不涉及任何素数/非素数的属性,让我们看看BCNF和2/3的NF是如何相关的。
首先,BCNF要求(除了微不足道的情况)对于每个函数依赖X -> Y
(FD),X应该是超级密钥。 如果只考虑任何FD,则有三种情况 – (1)X和Y非素数,(2)素数和(3)X素数和Y非素数,丢弃(不确定) -prime和Y prime。
对于情况(1),3NF照顾。
案件(3),2NF照顾。
对于情况(2),我们发现使用BCNF