详解数据库设计中的三大范式理论

一.第一范式(Normal Form,1NF)

  • 第一范式的目标是确保每列的原子性.如果每列(或每个属性值)都是不可再分的最小数据单元(也称为最小的原子单元),则满足第一范式
  • 例如表1:
    表1:客人住宿信息表
客人编号 姓名 地址 客房号 客房描述 客房类型 客房状态 床位数 价格 入住人数
C1001 张三 addr1 1001 a栋1层 单人间 入住 1 128 1
C1002 李四 addr2 2002 b栋2层 标准间 入住 2 168 1
  • 其中地址列还可细分为国家,省,市,区等,甚至更多程序把姓名列分为两列
  • 如果业务需求中不需要继续拆分,那么该表就已经符合第一范式

二.第二范式(2NF)

  • 第二范式在第一范式的基础上更进一层,其目标是确保表中的每列都和主键相关
  • 如果一个关系满足第一范式并且除了主键以外其他列全部依赖于该主键,则满足第二范式
  • '姓名’列,'地址’列->’客人编号’列
  • '客房描述’列,'客房类型’列,'客房状态’列,'床位数’列,'入住人数’列,'价格’列->’客房号’列
  • 其中->符号表示依赖
  • 以上各列没有全部依赖于主键(客人编号,客房号),只是部分依赖于主键.违背了第二范式的规定,所以在使用第二范式的原则对客人住宿信息表进行规范化之后分解成以下两个表:
  • 1)客人信息表(客人编号,姓名,地址,客房号,入住时间,结账日期,押金,总金额等),主键为’客人编号’,其他列全部依赖于主键
  • 2)客房信息表(客房号,客房描述,客房类型,客房状态,床位数,入住人数,价格等),主键为’客房号’,其他列全部依赖于主键

三.第三范式(3NF)

  • 第三范式在第二范式的基础上更进一层,第三范式的目标是确保每列都和主键列直接相关,而不是间接相关
  • 如果一个关系满足第二范式,并且除了主键以外其他列都只能依赖于主键,列和列之间不存在互相依赖关系,则满足第三范式
  • 为了理解第三范式,需要根据Armstrong公理(从已知的一些函数依赖可以推导出另外一些函数依赖)来定义传递依赖,分析如下
    假设A,B,C是关系R的三个属性,如果A->B且B->C 则从函数依赖中得出A->C(依赖的传递性)
 以第二范式中的客房信息表为例,初看时该表没得问题,满足2NF,每列都和主键列'客房号'相关,然而细看后发现:
 '床位数','价格'-->'客房类型''客房类型'-->'客房号''床位数','价格'-->'客房号'列
 为了满足3NF,应该去掉'床位数','价格','客房类型',将客房信息表分解为如下两个表:
 '客房表(客房号,客房描述,客户类型编号,客房状态,入住人数等)'
 '客房类型表(客房类型编号,客房类型名称,床位数,价格)'
 又因为第三范式也是对字段冗余性的约束,即任何字段不能由其他字段派生出来(除主键外,列列无关)
 冗余解释:
 	主键与外键在多表中的重复出现不属于数据冗余,非键字段的出现才是数据冗余
 在上述客房表中客房状态存在冗余,需要进行规范化,规范化的表如下:
 '客房表(客房号,客房描述,客户类型编号,客房状态编号,入住人数等)'
 '客房状态表(客房状态编号,客房状态名称)'

四.解析表1:客人住宿信息表的客房实体

  • 1)是否满足第一范式:
第一范式的要求每列必须是最小的原子单元,即不能再次细分,在这里地址无需再次分解,可认为满足第一范式
  • 2)是否满足第二范式:
第二范式要求每列都与主键相关,不想关的列放到别的表中,要求一个表只描述一件事情
该表描述了两件事情:客人信息和客房信息,因此不满足第二范式需要拆分
拆分后的两个表如下:
表2:客人信息表
客人编号 姓名 地址
C1001 张三 addr1
C1002 李四 addr2
表3:客房信息表
客房号 客房描述 客房类型 客房状态 床位数 价格 入住人数
1001 a栋1层 单人间 入住 1 128 1
2002 b栋2层 标准间 入住 2 168 1
  • 3)是否满足第三范式:
第三范式要求表中各列必须和主键直接相关,不能间接相关,即需要拆分客房信息表为客房表,客房类型表和客房状态表,如下:
表4:客房表
客房号 客房描述 客房类型编号 客房状态 入住人数
1001 a栋1层 1 1 1
2002 b栋2层 2 1 1
表5:客房类型表
客房类型编号 客房类型名称 床位数 价格
1 单人间 1 128
2 标准间 2 168
表6:客房状态表
客房状态编号 客房状态名称
1 入住
2 空闲
3 维修

五.规范化和性能之间的关系

需要提醒的是,对于项目的最终用户来说,客户最关心的是方便清晰的结果

在设计数据库时,设计人员和客户对数据库的设计规范化和性能之间存在一定的矛盾,
前面我们通过三大范式分解出很多个表,为了满足用户的需求,最终需要通过这么多的表之间连接查询,
获取用户需要的数据.插入数据也同样如此,对于客户输入的数据,需要分开插入到这么多的表
由此可看出,为了满足三大范式,数据操作性能会受到相应的影响.所以,在实际的数据库设计中,
既要考虑三大范式,避免数据冗余和各种数据操作异常;也要考虑数据访问性能.
有时为了减少表之间的连接,提高数据库访问性能,
允许适当的数据冗余列,这可能时最合适的数据库设计方案-->以空间换时间的方案

不要轻易地违反数据库设计的规范化原则若处理的不好,可能会适得其反,适得应用程序运行速度更慢

六.三大范式总结

1NF:列的原子性
2NF:每列必须和主键相关
3NF:各列必须与主键直接相关,不可间接相关,除主键外,其他列不得相关

猜你喜欢

转载自blog.csdn.net/sun_0128/article/details/107076171
今日推荐