规范化可以使数据库更加适应数据结构的变化,使数据库抵御某些类型的错误。数据库规则从弱到强的次序:第一、二、三范式,Boyce_Codd范式,第四、五范式,域/键范式(DKNF)
第一范式:
列名唯一;
行列次序无关;(若有次序要求,则加列priority)
每列数据类型唯一;
两行不同;(相同则加列quantity)
每列单值;(妻子列不能写多个名字)
列不包含重复的组。(不要建家畜1,家畜2,……等重复的列)
第二范式:
符合第一范式;
所有的非键值字段均依赖所有的键值字段。
例子:歌手、演出时间、歌手等级、歌手类型
问题:歌手和演出时间构成主键,但等级和类型都不依赖演出时间(属于键值字段)。
异常:
若更改了某一时段的歌手类型,其他时间段的该歌手类型冲突。
在增加一个歌手时,必须同时增加演出时间。
若取消了歌手的某一时间的表演,可能该歌手的全部信息就会丢失。
解决:将等级和类型移到新表中。
第三范式:
符合第二范式;
一个非键值字段不依赖于另一个非键值字段。(即不包含传递相关性)
例子:读者、书名、作者、出版时间
问题:书名依赖读者,而其他字段又依赖书名。
异常:
若修改了一本书的出版时间,而其他行的该书的时间则冲突。
必须在确定读者的情况下才能插入一本新书。
删除一读者可能会丢失一本书的信息。
解决:将作者、出版时间移到新表中。
Boyce_Codd范式(BCNF):
符合第三范式;
每个决定因子都是一个候选建。
概念:
超键:包含唯一值的一组字段。(既能够标识表中某个特定的行)
候选键:最小的超键。(即从候选键中删除任一列,将不再是超键)
决定因子:决定另一字段取值的字段
例子:学号、姓、名字、职务(一名学生可有多个职务,一个职务也可有多个学生)
问题:学号决定了姓和名字,但学号不是一个候选键。(学号+职务才是候选键)
异常:
若更改了一员工的姓,其他行该员工的姓则发生冲突。
不给学生指派职务,则无法添加学生记录。
删除一职务,可能会删除该学生的记录。
解决:将姓,名字移到新表中。
第四范式:
符合BCNF;
不包含无关的多值依赖性。
概念:
无关的多值依赖性:技能依赖员工,工具依赖员工,但技能和工具是独立的。
例子:员工,技能,工具(一个员工可有n种技能,m种工具)
问题:技能、工具具有无关的多值依赖性
异常:
一名员工的技能修改了,其他工具对应的技能则冲突。
一名员工丢失了一技能,需删除对应的n行。
一名员工增加一技能,必须增加对应的n行。
解决:将技能和工具放在两个表中,分别和员工关联。
第五范式:
符合第四范式;
不包含相关的多值依赖性。
概念:
相关的多值依赖性:汽车品牌依赖修理工,发动机类型依赖修理工,但品牌和发动机类型是相关的。
例子:修理工,汽车品牌,发动机类型
问题:品牌和发动机类型具有相关的多值依赖性。
解决:将品牌和发动机类型放在两个表中,与修理工关联;
同时还要有个品牌和发动机的关联表。
域/键范式(DKNF):
除了域约束和键约束外,该表不包含其他约束。
概念:
域约束:字段的值满足属于其域内的值。
键约束:构成一个键的字段中的值是唯一的。
例子:名字,省份,城市,区,邮编
问题:省份/城市/区与邮编存在约束,该约束不是域约束或键约束。
若将邮编拿出来则是DKNF,但我国的邮编有上千个,且有时还会变化。这样表的规模就很庞大,维护也不方便。所以有时也需要必要的冗余。
符合DKNF该范式的数据库,可以避免所有的数据异常;但有时满足该范式需要花费很大的代价,使维护很困难。一般较低级别的规范化就能得到足够好的结构,大多数情况不需要采用该范式。
注:本文参考《数据库设计解决方案入门经典》(美)Rod Stephens著 王海涛 宋丽华译 一书