数据库范式指数据库设计所需要满足的规范。符合这些规范的数据库结构明晰,避免INSERT,DELETE和UPDATE操作异常。
1 第一范式(1NF):数据库表中的字段都是单一属性的,不可再分。这个单一属性有基本类型构成(整型,实数,字符型,逻辑型,日期型等)。
在现有的DBMS中设计不符合1NF的数据库是不可能的(现有的DBMS不可以把某列再分2列或多列),所以可以“忽视”它。
2 第二范式(2NF):数据库表中不存在非关键字段对任一候选关键字段的部分函数依赖(部分函数依赖指的是存在组合关键字的某些字段决定非关键字段的情况),也即所有非关键字段都完全依赖于任意一组候选关键字。
比如:一个选课关系表select_course (学号, 姓名, 年龄, 课程名称, 成绩, 学分),关键字为组合字段(学号,课程名称),即(学号,课程名称)-> (姓名,年龄,成绩,学分)。
以上表并不符合2NF,因为(学号)-> (姓名,年龄);(课程名称)->(成绩,学分),即存在组合字段中的字段决定非关键字。
则存在问题有:
1)插入异常:
若想输入一门新课程,但还未有人选修(即没有“学号”这个关键字),便无法记录该新课程。
2)更新异常:
若调整了某一门课程的学分,则匹配该课程的所有行的学分都需要更新,否则出现一门课程多个学分情况。
3)数据冗余:
同一门课程由n个学生选修,”学分”就重复n-1次;同一个学生选修了m门课程,姓名和年龄就重复了m-1次。
所以,可改为以下几个表(符合2NF):
student (学号,姓名,年龄)
course(课程名称,学分)
select_course (学号,课程名称,成绩)
也可以发现,所有单关键字的数据库表都符合第二范式,因为不可能存在组合关键字。
3 第三范式(3NF):在第二范式的基础上,数据表中如果不存在非关键字段对任一候选关键字段的传递函数依赖。
传递函数依赖,指的是如果存在“A -> B -> C” 的决定关系,则C传递函数依赖于A。
比如:student(学号,姓名,年龄,所在学院,学院地点,学院电话),关键字段为“学号”。这表符合2NF,但不符合3NF,因为有以下关系:
(学号)->(所在学院)->(学院地点,学院电话) (即存在非关键字段“学院地点”,“学院电话”对关键字段“学号”的传递函数依赖),其存在的异常就不再详述。
分解符合3NF的表如下:
学生:(学号,姓名,年龄,学院ID)
学院:(学院ID,学院地点,学院电话)
4 鲍依斯-科得范式(BCNF):在第三范式的基础上,数据库表中如果不存在任何字段对任一候选关键字段的传递函数依赖。
比如:仓库管理表store_manage(仓库ID,物品ID,管理员ID,数量)。一个管理员只能一个仓库工作,一个仓库可以存储多种物品,即有如下决定关系:
(仓库ID,管理员ID)->(物品ID,数量)
(管理员ID,物品ID)->(仓库ID,数量)
可以看出,(仓库ID,管理员ID)和(管理员ID,物品ID)都是表store_manage的候选关键字,“数量”是唯一的非关键字段,故符合3NF。但又可以看出有如下关系:
(仓库ID)->(管理员ID)和(管理员ID)->(仓库ID),存在关键字段觉得关键字段的情况,不符合BCNF。出现的异常情况有:
1)插入异常:
仓库不存在物品时,不可加入“管理员ID”
2)更新异常:
需要更改某个“管理员ID”,需要改动多行,如果某行未改动,则会存在一个仓库有2个或多个管理员。
3)删除异常:
若需要清空某一仓库,其所有的“物品ID”和“数量”清空的同时,“管理员ID”和“仓库ID”也被清空了。
修改(符合BCNF):
仓库表:store(仓库ID,物品ID,数量)
仓库管理表:store_manage(仓库ID,管理员ID)
5 还有4NF,5NF,极少用到,略过。
满足范式要求的数据库设计是结构清晰的,同时可避免数据冗余和操作异常等。在多个实践中,有时适当的冗余,即不符合范式要求的设计,可以换来性能效率的提高,这很值得考虑~