数据库讲解

给某位同学

什么是范式等级

要说范式等级,我们得从一个很有意思的场景说起。
想象一下,你要去整理一个满是书籍的书架。书多得很,各种类型都有,历史的、科学的、小说的,乱七八糟堆在一起。你想要让书架看起来整齐一点,于是开始动手分类。最开始你想:“嗯,简单点,按书的种类来分吧,历史放一块,小说放一块。”这样你能更快找到书。这就是第一范式的感觉——有点儿像在数据库里,确保所有的数据都能被简单而明确地分类,避免乱糟糟的重复。
可你后来发现,光按种类分还是有点混乱,比如同一本书既是历史书又是小说,这该怎么办呢?于是你决定:“再细一点,按作者再分类吧。” 这样你不仅能知道书的种类,还能很快找到哪个作者写了哪些书。这时候,你的书架就更整齐了。这种多维度的分类管理就好比数据库里的第二范式,不仅要求数据要分类清楚,而且关联信息之间也不能有混乱和多余。
不过,事情远没结束。想象一下,有些书的出版社和年份也很重要,你觉得:“嗯,那我再把出版社和出版年份也加进去,分清楚。” 这时候,你不仅知道这本书是什么类型、谁写的,还知道它的出版社和出版时间。你的书架已经非常有条理了,这就像是数据库的第三范式,每一块信息之间都非常清晰独立。
到这里,你的书架已经相当有序了。可如果你是个完美主义者,还会更进一步,比如分类再细一点:每种书再按照出版顺序排列,甚至每个分类之间的细节也考虑进去。这种深入细节、几乎不容一点点混乱的分类方法,在数据库范式里对应的是BCNF范式(巴库斯-科德范式),也是一种非常严格的数据管理方式。
总结一下范式等级,范式是为了让数据“书架”整齐不混乱的规则。每往高一级范式走,数据的管理就变得更精细、逻辑更清楚,从第一范式到BCNF范式,数据的重复和冗余也一步步减少。就像你整理书架时从只考虑种类,到逐渐按作者、出版社、出版年等各种维度来分类,最终让书架井然有序。
你大概现在能理解,范式就是为数据库设计的“整理书架”的规则,每一个范式等级都是对数据如何更整齐、避免混乱的一次升级。
 
假设我们有一个存储图书信息的数据库,初始表格设计如下:
图书编号
书名
作者
出版社
出版年份
作者出生地
1
明朝那些事儿
当年明月
某出版社
2006
中国
2
三国演义
罗贯中
某出版社
2001
中国
3
红楼梦
曹雪芹
某出版社
1980
中国
4
明朝那些事儿
当年明月
另一家出版社
2009
中国
这是我们的初始表,里面看似没啥问题,但其实在范式上存在不少可以优化的地方。接下来我们一层层地看看怎么优化。

第一范式(1NF)

要求:每个字段都必须是原子值,也就是表中的每一列都不能有“多值”或“重复分组”。
如果我们的表是这样的:
图书编号
书名
作者
出版社
出版年份
作者出生地
1
明朝那些事儿
当年明月,张三
某出版社,另一家出版社
2006, 2009
中国, 英国
这就违反了第一范式,因为有些字段(比如作者、出版社)包含了多个值。为了符合第一范式,我们得把每条数据拆开,确保每个字段都是单一的、不可分割的值:
图书编号
书名
作者
出版社
出版年份
作者出生地
1
明朝那些事儿
当年明月
某出版社
2006
中国
2
明朝那些事儿
当年明月
另一家出版社
2009
中国
这样每条记录都变得原子化,不存在多个值的问题了。

第二范式(2NF)

要求:首先符合1NF;其次,非主属性必须完全依赖于主键。简单来说,不能有部分依赖的情况。
在这里,我们的主键可以是“图书编号”,现在看一下这个表:
图书编号
书名
作者
出版社
出版年份
作者出生地
1
明朝那些事儿
当年明月
某出版社
2006
中国
2
三国演义
罗贯中
某出版社
2001
中国
3
红楼梦
曹雪芹
某出版社
1980
中国
在这个表里,"作者出生地"(比如“当年明月是中国人”)跟"图书编号"没啥直接关系,它跟"作者"有关系。这就是部分依赖了,因为"作者出生地"的值依赖于"作者",而不是图书编号。
为了达到第二范式,我们需要把表拆分成两张表,一张专门记录图书信息,另一张专门记录作者信息:
图书表
图书编号
书名
作者
出版社
出版年份
1
明朝那些事儿
当年明月
某出版社
2006
2
三国演义
罗贯中
某出版社
2001
3
红楼梦
曹雪芹
某出版社
1980
作者表
作者
作者出生地
当年明月
中国
罗贯中
中国
曹雪芹
中国
这样就避免了"作者出生地"和"图书编号"的部分依赖问题,每个信息都依赖它该依赖的属性。

第三范式(3NF)

要求:首先符合2NF;其次,消除传递依赖,也就是说非主属性不能依赖于其他非主属性。
在上面的“图书表”里,我们发现“出版社”和“出版年份”也存在传递依赖。比如,某些书如果在同一家出版社多次出版,那我们就得重复写好多次出版社的信息。
为了符合第三范式,我们可以再进一步把表拆分:
图书表
图书编号
书名
作者
出版社编号
出版年份
1
明朝那些事儿
当年明月
1
2006
2
三国演义
罗贯中
1
2001
3
红楼梦
曹雪芹
1
1980
出版社表
出版社编号
出版社名称
1
某出版社
2
另一家出版社
通过这种方式,我们避免了在多个地方重复记录出版社的信息。如果以后某个出版社的名字变了,修改出版社表就行了,不需要去改很多行记录。

BCNF范式(Boyce-Codd范式)

要求:BCNF是对3NF的更进一步强化,要求每个决定性字段必须是超键。
假如我们的数据表有这样一种情况:一个作者可能签约多个出版社,一个出版社可能签约多个作者。这时候,出版社和作者之间的关系会导致依赖问题。这种情况我们需要把"作者"和"出版社"的关联关系也独立出来,形成一个专门的关联表:
作者-出版社关联表
作者
出版社编号
当年明月
1
当年明月
2
罗贯中
1
通过这样的关联表,所有的关系都变得非常清晰,不会再有重复或冗余的数据。

总结

通过这个例子,我们从最初的“乱书架”,一步步整理到了高效、有序的数据库表结构。从第一范式的基本整理,到第三范式和BCNF的严格依赖管理,范式的每一步优化都是为了减少数据冗余、提升数据的逻辑结构。