数据库设计第三范式
一、数据库设计范式及其意义和不足
数据库的设计范式是数据库设计所需要满足的规范,数据库的规范化是优化表的结构和优化把数据组织到表中的方式,这样使数据更明确,更简洁。实践中,通常把一个数据库分成两个或多个表并定义表之间的关系以做到数据隔离,添加、删除和修改某个字段只需要在一个表中进行,接着可以通过定义的关系传递到数据库中剩余的表中(和分层思想的意义所在很相似)。这样我们可以消除很多错误或垃圾数据出现的机会并减轻更新信息所必要的工作量。
目前,主要有六种范式:第一范式、第二范式、第三范式、BC范式、第四范式和第五范式。满足最低要求的叫第一范式,简称1NF。在第一范式基础上进一步满足一些要求的为第二范式,简称2NF。其余依此类推
事物往往具有多面性,设计范式也会带来一定的麻烦:操作困难,因为需要联系多个表才能得到所需要数据,而且范式越高性能就会越差。所以使用多高的范式需要权衡利弊,一般在项目中,使用到第三范式也就足够了,性能好而且方便管理数据。
二、下面我们来举例介绍一下数据库设计三范式
说明:实例采用《学校机房收费系统》的“学生信息表”,“学生上下机记录表”的部分字段
1、第一范式1NF
定义:数据库表中的字段都是单一属性的,不可再分。
简单的说,每一个属性都是原子项,不可分割。
1NF是关系模式应具备的最起码的条件,如果数据库设计不能满足第一范式,就不称为关系型数据库。也就是说,只要是关系型数据库,就一定满足第一范式。
我们先来看一张不符合1NF的表1-1
CardNo | StudentNo | StudentName | Sex | Department | CardCash | UserID | UserLevel | Time |
001 | 021101 | 小明 | 男 | 教育学院,心理系,1班 | 100 | Operator | 操作员 | 2011/10/03,09:00 |
之所以说这张表不符合1NF,是因为Department和Time字段可以再分,所以应该更改为表1-2:
CardNo | StudentNo | StudentName | Sex | Academy | Major | class | CardCash | UserID | UserLevel | Date | Time |
001 | 021101 | 小明 | 男 | 教育学院 | 心理系 | 1 | 100 | Operator | 操作员 | 2011/10/03 | 09:00 |
2、第二范式2NF
定义:数据库表中不存在非关键字段对任一候选关键字段的部分函数依赖,即符合第二范式。
《注:什么是函数依赖,详见百度百科(http://baike.baidu.com/view/40008.htm)。
如果一个表中某一个字段A的值是由另外一个字段或一组字段B的值来确定的,就称为A函数依赖于B。》
2NF可以减少插入异常,删除异常和修改异常。
简单的说,一方面,第二范式肯定要满足第一范式,否则就没有必要谈第二范式。
另一方面,当某张表中的非主键信息不是由整个主键函数来决定时,即存在依赖于该表中不是主键的部分或者依赖于主键一部分的部分时,通常会违反2NF。
我们再来看上面的满足1NF的表1-2
CardNo | StudentNo | StudentName | Sex | Academy | Major | class | CardCash | UserID | UserLevel | Date | Time |
001 | 021101 | 小明 | 男 | 教育学院 | 心理系 | 1 | 100 | Operator | 操作员 | 2011/10/03 | 09:00 |
我们看到,在这张表中,通过CardNo和StudentNo就可以确定StudentName,Sex,Academy,Major,class,CardCash,UserID,Date,Time。所以可以把CardNo和StudentNo的组合作为主键。
但是,我们发现CardCash并不完全依赖于CardNo和StudentNo,仅仅通过CardNo就可以确定CardCash,因为一张卡,一定会有卡内金额。这就造成了部分依赖。出现这种情况,就不满足第二范式。
修改为:
我们再来看另一个例子,学生上下机记录表,会更明显些。表2-1
CardNo | StudentNo | StudentName | Sex | Department | Major | class | OnDate | OnTime | OffDate | OffTime | ConsumeTime | ConsumeMoney |
001 | 0211 | 小明 | 男 | 教育学院 | 心理系 | 1 | 2011/10/14 | 09:00 | 2011/10/14 | 10:00 | 1 | 2 |
我们看到,在这张表中,StudentName,Sex,Department,Major,class都是直接依赖于StudentNo,而不依赖与表中的其他字段,这样的设计也不符合2NF非主键信息不是由整个主键函数来决定时。
我们可以把1-2和2-1优化为:
3-1
StudentNo | CardNo | UserID | UserLevel | Date | Time |
021101 | 001 | Operator | 操作员 | 2011/10/03 | 09:00 |
3-2
CardNo | CardCash |
001 | 98 |
3-3
CardNo | OnDate | OnTime | OffDate | OffTime | ConsumeTime | ConsumeMoney |
001 | 2011/10/14 | 09:00 | 2011/10/14 | 10:00 | 1 | 2 |
3-4
StudentNo | StudentName | Sex | Academy | Major | class |
021101 | 小明 | 男 | 教育学院 | 心理系 | 1 |
3、第三范式3NF
定义:在第二范式的基础上,数据表中如果不存在非关键字段对任一候选关键字段的传递函数依赖则符合3NF。
我们来看上例中优化后的表3-1
StudentNo | CardNo | UserID | UserLevel | Date | Time |
021101 | 001 | Operator | 操作员 | 2011/10/03 | 09:00 |
在表中,一个UserID能确定一个UserLevel。这样,UserID依赖于StudentNo和CardNo,而UserLevel又依赖于UserID,这就导致了传递依赖,3NF就是消除这种依赖。
我们把3-1进行优化得到:
4-1
StudentNo | CardNo | UserID | Date | Time |
021101 | 001 | Operator | 2011/10/03 | 09:00 |
4-2
UserID | UserLevel |
Operator | 操作员 |
我们看到,第三范式规则查找以消除没有直接依赖于第一范式和第二范式形成的表的主键的属性。我们为没有与表的主键关联的所有信息建立了一张新表。每张新表保存了来自源表的信息和它们所依赖的主键。
三、总结
数据库设计规范化能让我们更好地适应变化,使你能够改变业务规则、需求和数据而不需要重新构造整个系统。