数据库范式应用

学习数据库范式理论后,尽管已经知道范式能够帮助优化数据库设计,但是在使用中却发现,很难将这些理论方便的应用到实际中。本节主要梳理下如何在实际应用中使用范式。
范式有很多种,参考关系数据库设计可知有第一范式、第二范式、第三方式、BC范式、第四范式、第五范式、域-码范式等。

第一范式

当关系模式满足第一范式时,该关系模式所有属性的域都是原子的。常见的非原子域实例如下:

  • (1) 组合属性具有非原子域。如包含子属性street、city、state和zip的属性address。
  • (2) 使用以集合为值的属性会导致冗余存储数据的设计,进而会进一步导致不一致。如数据库设计者可能不将教师和课程安排之间的联系表示为一个单独的关系teaches,而是尝试为每一个教师存储一个课程段标志号的集合,并为每一个课程段存储一个教师标志号的集合。每当关于哪位教师讲授哪个课程段的数据发生变化时,就需同时更新两个地方:课程段的教师集合和教师的课程段集合。对这两个更新的执行失败,会导致数据库处于不一致的状态。如果只保留一个,将避免信息的重复。但是,只保留一个会导致某些查询变得复杂,并且也不好确定保留哪一个。(在设计数据库时,要注意这种误区)
  • (3) 有时,非原子值也有其价值。在许多含有复杂结构的实体域中,强制使用第一范式会给应用程序带来不必要的负担,如必须编写代码把数据转换成原子形式。从原子形式来回转换数据也会有运行时额外开销。所以,这种场景支持非原子的值很有用。事实上,现代数据库的确支持很多类型的非原子值。如支持创建复合属性、集合、数组等复杂数据类型。

简单来说,第一范式要求属性的域都是原子的(不可再分)。对于多值属性,为多值集合中的每一项创建一条元组。所以无需考虑。注意,这里只讨论是否满足第一范式,对于属性中包含非原子值的场景,这里不进行扩展讨论。
第一范式只是关系模式众多范式中最基础的一个模式,其本身依旧存在许多致命的问题。如数据冗余,插入、删除、更新等异常。假设关系模式R为:

(学生ID,姓名,课程号,课程名,所在系,系主任,成绩)

数据冗余

上述关系模式属于第一模式。然而这样的关系模式什么问题呢?比如从数据冗余角度来说,我们有理工大类学生A,选了数学与英语课。那么在关系模式中则会存有两个字段:

(A_ID1,A,课程号1,数学,理工大类,AAA,1.0)

(A_ID2, A,课程号2,英语,理工大类,AAA,1.0)

从这里可以看出,除了课程的相关属性,其他属性完全一样,这明显是数据冗余。

插入异常

如果来一个转学生B,转学生B如果没有选课,但是学生信息必须先录入,那该怎么办呢?录入数据如下:

(B_ID,B,NULL,NULL,理工大类,AAA,NULL)

当我们在录入课程号和课程名时,完全无法填写,只能插入空值,如果添加了对课程号和课程名的非空校验,那么将无法插入新记录,从而造成插入异常。

更新异常

若调整了某门课程的学分,数据表中所有行的”学分”值都要更新,否则会出现同一门课程学分不同的情况。

删除异常

假设一批学生已经完成课程的选修,这些选修记录就应该从数据库表中删除。但是,与此同时,课程名称和学分信息也被删除了。

BC范式

第二范式(Second Normal Form, 2NF)只具有历史的意义,并没有在实际中使用。这里着重介绍BC范式。
Boyce-Codd范式可以消除所有基于函数依赖能够发现的冗余。具有函数依赖集F的关系模式R属于BCNF的条件是,对 F + F^+ F+中所有形如α → \rightarrow β的函数依赖(α ⊆ \subseteq R且β ⊆ \subseteq R),下面至少有一项是成立:

  • α → \rightarrow β是平凡的函数依赖(即β ⊆ \subseteq α)。
  • α是模式R的一个超码。

也就是说,对于满足BC范式的关系模式,这个关系模式中的所有函数依赖,要么该依赖是平凡的函数依赖(存在包含关系),要么函数依赖的左侧部分是超码。所以判断函数是否遵循BCNF,可以按照如下步骤判断:

if 该函数依赖是平凡的依赖
    该函数依赖遵循BCNF
    return true
else if 该函数依赖的左侧部分是超码
    该函数依赖遵循BCNF
    return true
else
    该函数依赖不遵循BCNF
    return false

只要关系模式中存在一个函数依赖不遵循BCNF,那么该关系模式就不满足BC范式。

举例说明

如果需要使用仓库存储物品,且每个仓库只有一个管理员,且定义仓库管理关系表为StoreHouseManage(仓库ID, 存储物品ID, 管理员ID, 数量),那么这个数据库表有如下函数依赖:

  • (仓库ID, 存储物品ID) → \rightarrow (管理员ID, 数量)
  • (管理员ID, 存储物品ID) → \rightarrow (仓库ID, 数量)
  • (仓库ID) → \rightarrow (管理员ID)
  • (管理员ID) → \rightarrow (仓库ID)

由于管理员ID和仓库ID的一对一映射关系,所以(仓库ID, 存储物品ID)和(管理员ID, 存储物品ID)都可作为StoreHouseManage的候选码。因为函数依赖(仓库ID) → \rightarrow (管理员ID) 和 (管理员ID) → \rightarrow (仓库ID)的左侧部分均不是超码,所以不满足BCNF范式。
对于不属于BCNF的范式,需要对其进行分解。设R为不属于BCNF的一个模式,则存在至少一个非平凡的函数依赖α → \rightarrow β,其中α不是R的超码。那么在设计中可以使用以下两个模式取代R:

  • ⋃ \bigcup β)
  • (R - (β - α))

当分解不属于BCNF的模式时,产生的模式可能有一个或多个不属于BCNF。在这种情况下,需要进一步分解,其最终结果是一个BCNF模式集合。更多分解实现参考关系数据库设计的分解算法
对于上述示例,将仓库管理关系表分解为二个关系表:

  • 仓库管理:StoreHouseManage(仓库ID, 管理员ID)
  • 仓库:StoreHouse(仓库ID, 存储物品ID, 数量)

一次分解后,可以验证,上述两个关系模式都是满足BCNF的。
BCNF使得函数依赖的实施变得困难(有可能破坏关系模式上的函数依赖)。对于希望保持函数依赖,可以考虑另外一种比BCNF弱的范式——第三范式。

第三范式

第三范式是比BCNF弱的范式。任何满足BCNF的模式也满足3NF。具有函数依赖集F的关系模式R属于第三范式(third normal form)的条件是:对 F + F^+ F+中所有形如α → \rightarrow β的函数依赖(α ⊆ \subseteq R且β ⊆ \subseteq R),下面至少有一项是成立:

  • α → \rightarrow β是平凡的函数依赖(即β ⊆ \subseteq α)。
  • α是模式R的一个超码。
  • β - α中的每一个属性A都包含于R的一个候选码中。

前两个条件与BCNF定义中的两个条件相同。第三个条件,在某种意义上,代表BCNF条件的最小放宽,以确保每一个模式都有保持依赖的3NF分解。对于判断一个函数依赖是否遵循第三范式,可以按照如下步骤判断:

if 该函数依赖是平凡的依赖
    该函数依赖遵循3NF
    return true
else if 该函数依赖的左侧部分是超码
    该函数依赖遵循3NF
    return true
else if 该函数依赖的右侧部分去除与左侧部分重复的属性后剩余的属性均在候选码中
    该函数依赖遵循3NF
    return true
else 
    该函数依赖不遵循3NF
    return false

BCNF和3NF比较

BCNF可以消除所有基于函数依赖所能发现的冗余(注意,BCNF不能确保冗余被消除),但无法保证设计是保持依赖的。
3NF可以在满足无损的同时并保持依赖。但3NF也有一个缺点:可能不得不用空值表示数据项间的某些可能有意义的联系,并且存在信息重复的问题。
对使用函数依赖进行数据库设计的目标是:

  1. BCNF
  2. 无损
  3. 保持依赖

由于不是总能达到所有三个目标,因为我们需要在BCNF和保持依赖的3NF中做出选择。
在不能得到保持依赖的BCNF分解的情况下,通常我们倾向于选择BCNF,因为在SQL中检查非主码约束的函数依赖很困难。

第四范式

函数依赖可以消除函数依赖发现的冗余,对于无法由函数依赖发现的冗余,则不能保证一定被消除。如多值依赖产生的冗余。
函数依赖和多值依赖集为D的关系模式r®属于第四范式(4NF)的条件是,对 D + D^+ D+中所有形如α → \rightarrow → \rightarrow β的多值依赖(其中α ⊆ \subseteq R且β ⊆ \subseteq R),至少有以下之一成立:

  • α → \rightarrow → \rightarrow β是一个平凡的多值依赖。
  • α是R的一个超码。

可以看到,4NF定义与BCNF定义的唯一不同在于多值依赖的使用。与BCNF类似,4NF可以消除所有基于多值依赖能够发现的冗余,同时无法保证设计是保持依赖的。相比函数依赖,多值依赖的保持问题更加复杂,这里不扩展讨论。更多该问题的讨论可参考《数据库系统概念》一书的附录C.1.2。
判断一个多值依赖是否遵循第四范式,可以按照如下步骤判断:

if 该多值依赖是平凡的多值依赖
    该函数依赖遵循4NF
    return true
else if 该多值依赖的左侧部分是超码
    该函数依赖遵循4NF
    return true
else 
    该多值依赖不遵循4NF
    return false

四范式不是“最终”的范式。多值依赖有助于理解并消除某些形式的信息重复,而这种信息重复用函数依赖是无法理解的。

第五范式

还有一些类型的约束称作连接依赖(join dependency),它概化了多值依赖,并引出了另一种范式称作投影-连接范式(Project-Join Normal Form, PJNF)(PJNF在某些书中称为第五范式,fifth normal form)。PJNF不仅难以推导,而且没有形成一套具有正确有效性和完备性的推理规则用于约束的推导。因此PJNF很少使用。

域-码范式

还有一类更一般化的约束,它引出一种称作域-码范式(Domain-Key Normal Form, DKNF)。同PJNF一样,DKNF不仅难以推导,而且没有形成一套具有正确有效性和完备性的推理规则用于约束的推导。因此DKNF也很少使用。

第二范式

第二范式(Second Normal Form, 2NF)只具有历史的意义(没有实用意义),所以没有对它进行深入讨论。关系模式R属于第二范式,如果R中的每个属性A都满足如下准则之一:

  • (1) 它出现在一个候选码中。
  • (2) 它没有部分依赖于一个候选码。

函数依赖α → \rightarrow β称为部分依赖(partial dependency)的条件是,存在α的真子集γ使得γ → \rightarrow β。我们称β部分依赖于α。

其他范式

范式并没有终点,更多的认识问题,会有更多的范式出现。

如何选用范式

一般情况下,数据库设计至少保证第三范式,对于是否保证BC范式或第四范式,还需根据具体情况判断。所以在范式的实际应用中,第一范式必须满足, 第三范式、BC范式、第四范式要根据实际需求进行权衡。这需要对实践的不断积累才能取舍。后续会不断补充这一部分。

参考

数据库系统概念(第六版) A. Silberschatz H. F. Korth S. Sudarshan著 杨冬青 等译 第八章
https://zhuanlan.zhihu.com/p/22337031 如何理解关系模式三范式?
https://www.cnblogs.com/awidy/articles/3978724.html 三大范式和BC范式

你可能感兴趣的:(数据库系统概念,big,data,数据库,知识图谱)