数据库设计,一个软件项目成功的基石。一个好的数据库设计能让开发人员在后续的开发中如鱼得水,反之,一个差的数据库设计简直就是四面漏风的墙。
数据库设计的规范化即范式。
1. 第1范式(1NF)
定义:如果关系模式R,其所有的属性均为简单属性,即每个属性都是不可再分的,则称R属于第一范式,简称1NF。
说明:1NF强调每一列必须为原子列且无概念性重复。
比如,表1中虽然每列都是原子列,但【选修1】【选修2】列,在概念上是重复的列。所以,表1不符合1NF。
以学生选修信息作为反面案例:
学生姓名 | 专业 | 辅导员 | 选修1 | 选修2 |
小明 | 计算机科学与技术 | 张三 | 古典音乐鉴赏 | 社会心理学 |
小强 | 集成电路 | 李四 | 中国古代名著赏析 | 电影艺术欣赏 |
小红 | 软件工程 | 王二 | 社会心理学 | 电影艺术欣赏 |
解决:消除表中重复列,为每个与重复列相关的数据建立一个独立的行。这样一来,解决了【选修】列的扩展性问题。通过以上遵守1NF的对策,得到了如下新表:
学生姓名 | 专业 | 辅导员 | 选修 |
小明 | 计算机科学与技术 | 张三 | 古典音乐鉴赏 |
小明 | 计算机科学与技术 | 张三 | 社会心理学 |
小强 | 集成电路 | 李四 | 中国古代名著赏析 |
小强 | 集成电路 | 李四 | 电影艺术欣赏 |
小红 | 软件工程 | 王二 | 社会心理学 |
小红 | 软件工程 | 王二 | 电影艺术欣赏 |
小明 | 软件工程 | 王二 | 古典音乐鉴赏 |
不过,这样仍有一个遗留问题和处理后带来的一个新问题,即
- 学生重名问题(计算机科学与技术的小明和软件工程的小明必然是重名,但计算机科学与技术的两行小明是一个人还是重名的两个人,难以断定)
- 数据冗余问题(每次为学生添加一门选修课时,都必须重复的插入学生,专业和辅导员的信息。这样一来,使数据出现冗余并容易出错)。
因此,还需要遵守2NF来解决问题。
2. 第2范式(2NF)
定义:如果关系模式R?1NF,且每个非主属性都完全函数依赖于R的每个关系键,则称R属于第二范式,简称2NF。
说明:2NF要求数据库表中的每行必须可以被惟一地区分,并且要求实体的属性完全依赖于主属性。
解决1:使用主键来标识相关数据。第2范式主要讨论了非主属性与主属性的关系问题,只有表中存在了主属性标识,才能继续这个问题。而在表2中,由于重名问题没有解决,并无可以标识主属性的一列或者几列。下面通过加入学生ID来标识主属性
学生ID | 学生姓名 | 专业 | 辅导员 | 选修 |
1 | 小明 | 计算机科学与技术 | 张三 | 古典音乐鉴赏 |
1 | 小明 | 计算机科学与技术 | 张三 | 社会心理学 |
2 | 小强 | 集成电路 | 李四 | 中国古代名著赏析 |
2 | 小强 | 集成电路 | 李四 | 电影艺术欣赏 |
3 | 小红 | 软件工程 | 王二 | 社会心理学 |
3 | 小红 | 软件工程 | 王二 | 电影艺术欣赏 |
4 | 小明 | 软件工程 | 王二 | 古典音乐鉴赏 |
解决2:消除不完全依赖于主键的非主属性,为其建立独立的新表,使用外键来与其关联。假设学校的体制是,一个学生有唯一的名字、专业、辅导员,那么,一旦确定了一个学生ID,则专业、辅导员也就被确定了。即,符合变量单值函数 y = f(x) 这种关系,则可以说学生姓名、专业、辅导员 函数依赖与主键学生ID(在主键是多个列的时候才能讨论是完全依赖还是部分依赖的问题,单列主键的情况下,函数依赖必是完全函数依赖),但一个学生可能有多个选修与其对应,因此选修不能被唯一确定,即选修不能函数依赖于学生ID。
通过解决2,把表3分解为两个表,表4-1和4-2。
学生ID | 学生姓名 | 专业 | 辅导员 |
1 | 小明 | 计算机科学与技术 | 张三 |
2 | 小强 | 集成电路 | 李四 |
3 | 小红 | 软件工程 | 王二 |
ID | 学生ID | 选修 |
1 | 1 | 古典音乐鉴赏 |
2 | 1 | 社会心理学 |
3 | 2 | 中国古代名著赏析 |
4 | 2 | 电影艺术欣赏 |
5 | 3 | 社会心理学 |
6 | 3 | 电影艺术欣赏 |
至此,一个学生添加新的选修时,已经不用重复加入专业信息了,但仍存在潜在的冗余问题。即,假设每个专业有唯一的辅导员,在某个专业新增学生(例如,计算机科学与技术新生小花),要向表4-1中插入小花的信息,这时,计算机科学与技术和其辅导员张三信息就会被重复插入,出现了冗余。下面的第三范式将解决这个问题。
3. 第3范式(3NF)
定义:如果关系模式R?2NF,且每个非主属性都不传递依赖于R的每个关系键,则称R属于第三范式(Third Normal Form),简称3NF。
说明:3NF致力于消除只是传递依赖与主键的非主属性。简而言之,就是属性不依赖于其它非主属性。
在表4-1中,虽然辅导员完全函数依赖于主键学生ID(即,一个学生ID能唯一确定他的辅导员),但在概念上这只是传递依赖而并非直接依赖。辅导员直接依赖的是专业,因为在概念上,一个专业才是辅导员存在的唯一原因。正是因为一个学生ID能唯一确定一个专业,而一个专业能唯一确定一个辅导员,所以说,辅导员对主键学生ID的依赖关系是传递依赖,而不是直接依赖。它直接依赖的是非主属性专业。
解决:为传递依赖于主键的属性建立独立的新表从而消除非主属性对主键的传递依赖关系。如此,将表4-1划分为以下两个表。
学生ID | 学生姓名 | 专业ID |
1 | 小明 | 1 |
2 | 小强 | 2 |
3 | 小红 | 3 |
专业D | 专业 | 辅导员 |
1 | 计算机科学与技术 | 张三 |
2 | 集成电路 | 李四 |
3 | 软件工程 | 王二 |
至此,辅导员信息重复的问题被解决。但还有一个遗留问题,即,表4-2中,选修名依然有重复。将通过第四范式来解决这个问题。下面简要介绍第四范式。
4. 第4范式(4NF)
概要:在多值依赖关系(多对多)中,独立的实体概念不能禁止存放在同一个表中。表4-2违反了这个规则,问题是,如果删除了学生ID为1的学生,则将导致选修课程信息丢失。
解决:为选修建立独立的表,为学生选修建立独立的表。
选修ID | 选修 |
1 | 古典音乐鉴赏 |
2 | 社会心理学 |
3 | 中国古代名著赏析 |
4 | 电影艺术欣赏 |
ID | 学生ID | 选修ID |
1 | 1 | 1 |
2 | 1 | 2 |
3 | 2 | 3 |
4 | 2 | 4 |
5 | 3 | 2 |
6 | 3 | 4 |
表5-1,5-2,6-1,6-2这四个表即是最终结果。
在实践中不管什么情况,都严格恪守设计范式来进行数据库设计 —— 不推荐
完全没有研究过设计范式就进行数据库设计 —— 极其不推荐