数据库设计三范式

文章转载自「开发者圆桌」一个关于开发者入门、进阶、踩坑的微信公众号数据库

wKioL1i5Ck7AkeuMAAChGHetiEM164.jpg

做为一个数据库的学习者,搞懂关系数据库的三大范式是颇有用的。然而有关数据库范式的介绍都是采用学术性的定义,语法羞涩,让人难懂,故写下本身对数据库范式的理解,给初学者提供帮助。微信


关系数据库中的关系必须知足必定的要求。知足不一样程度要求的为不一样范式。数据库的设计范式是数据库设计所须要知足的规范。只有理解数据库的设计范式,才能设计出高效率、优雅的数据库,不然可能会设计出错误的数据库。数据库设计


目前,主要有六种范式:第一范式、第二范式、第三范式、BC范式、第四范式和第五范式。知足最低要求的叫第一范式,简称1NF。在第一范式基础上进一步知足一些要求的为第二范式,简称2NF。其他依此类推。ide


范式能够避免数据冗余,减小数据库的空间,减轻维护数据完整性的麻烦,可是操做困难,由于须要联系多个表才能获得所须要数据,并且范式越高性能就会越差。要权衡是否使用更高范式是比较麻烦的,通常在项目中,用得最多的也就是第三范式,使用到第三范式也就足够了,性能好并且方便管理数据。性能


本文不介绍规范化程度高于3NF的范式,对于不少大型复杂的系统,其数据库设计都没有遵循所谓的范式,这也是为何会出现所谓的逆规范化,范式也须要考虑使用场景,不可一切东西都要范式化。在没有更多实践经验的状况下,遵循范式是很是好的选择。学习


在实例中理解三大范式
spa


1NF:字段不可分.net


强调的是列的原子性,即列不可以再分红其余几列。 设计


例1,学生信息表orm


学生编号 姓名 性别 联系方式

20080901 张三 男 email:zs@126.com,phone:88886666

20080902 李四 女 email:ls@126.com,phone:66668888

以上的表就不符合,第一范式:联系方式字段能够再分,因此变动为正确的是:

学生编号 姓名 性别 电子邮件 电话

20080901 张三 男 zs@126.com 88886666

20080902 李四 女 ls@126.com 66668888


例2,学生班级信息


学生编号 姓名 班级

20080901 小明 高三1班

20080902 小叶 高三2班

以上的表就不符合,第一范式:班级字段能够再分,因此变动为正确的是:

学生编号 姓名 年级 班级

20080901 小明 高三 1班

20080902 小叶 高三 2班


例3,员工信息表


员工编号 姓名 工做年限

20080901 小明 2009~2011

20080902 小叶 2006~2012

以上的表就不符合,第一范式:工做年限能够再分,因此变动为正确的是:

员工编号 姓名 工做年份 离职年份 

20080901 小明 2009 2011

20080902 小叶 2006 2012


例4,学生成绩表


学生编号 姓名 课程成绩

20080901 小明 80,70,90

20080902 小叶 60,70,85

以上的表就不符合,第一范式:课程成绩能够再分,因此变动为正确的是:

学生编号 姓名 语文 数学 外语

20080901 小明 80 70 90

20080902 小叶 60 70 85


例5,联系人信息表


姓名 性别 电话

小明  男   0101-3464554,13699170707

小叶  女   0101-3464674,13623450707

以上的表就不符合,第一范式:电话能够再分,因此变动为正确的是:

姓名 性别 座机 手机

小明  男   0101-3464554 13699170707

小叶  女   0101-3464674 13623450707


例6,公司信息表


公司编号 名称 地址

20080901 谷歌 美国加利福尼亚州圣克拉拉县山景市

20080902 百度 中国北京市海淀区上地十街10号百度大厦

以上的表就不符合,第一范式:地址能够再分,因此变动为正确的是:

公司编号 名称 国籍 地址

20080901 谷歌 美国 加利福尼亚州圣克拉拉县山景市

20080902 百度 中国 北京市海淀区上地十街10号百度大厦


对于例6地址的拆分可根据需求进行,不必定非要拆分。若是需知道哪一个国家并按其分类,那么显然第一个表格是不容易知足需求的,也不符合第一范式。所以是否符合第一范式的要求在必定程度上取决于后期对数据的查询和使用上,固然,第一范式是前人总结的通用方法,遵循它会获得意想不到的好处。



2NF:有主键,非主键字段依赖主键


首先是知足 1NF,另外包含两部份内容,一是表必须有一个主键;二是没有包含在主键中的列必须彻底依赖于主键。


主键很重要,要记住在设计表的时候不管如何也要添加主键,没有主键的表会给你带来噩梦般的体验,会给系统开发、功能维护、数据维护带来没必要要的麻烦。举个例子,上面例5,联系人信息表就没有添加主键,以下数据你想删除小明的信息该如何操做,根据姓名吗?不行,由于有重名的状况,只能经过姓名+电话两个字段组合为一个惟一的条件进行删除。


姓名 性别 电话

小明  男   0101-3464554,13699170707

小叶  女   0101-3464674,13623450707

小朱  女   0101-3464675,13623450705

小明  男   0101-3464676,13623450706


而有了主键,状况会是怎样的呢?你只须要根据联系人编号便可删除,一步到位。


联系人编号 姓名 性别 电话

1 小明  男   0101-3464554,13699170707

2 小叶  女   0101-3464674,13623450707

3 小朱  女   0101-3464675,13623450705

4 小明  男   0101-3464676,13623450706


切记,在任什么时候刻,一张表必定要有主键,若是你没法肯定业务中哪一个字段做为主键,那么你就创建一个ID字段做为主键,多一个ID字段不会影响什么。


例1,学生信息表(主键学号)


学号 姓名 性别 年龄 课程名称 学分

2008 张三 男 15 语文    45

2008 张三 男 15 数学    55

2009 李四 女 16 语文    45

2009 李四 女 16 数学    55

以上的表就不符合,第二范式:主键(学号)没法惟一肯定课程名称和学分,也就是说部分非主键字段不依赖主键,因此变动为正确的是:


学生信息表


学号 姓名 性别 年龄

2008 张三 男 15 

2008 张三 男 15 


课程表


课程名称 学分

语文     45

数学     55


学生选课表


学号  课程名称

2008  语文

2008  数学

2009  语文

2009  数学


例2,学生借书表


学生证号 学生证办理时间 借书证号 借书证办理时间

2008 2010年9月1号 201001  2010年10月1号

2009 2010年9月2号 201011  2011年10月1号

以上的表就不符合,第二范式:借书证号和借书证办理时间这些非主键字段不依赖学生证号这个主键,因此变动为正确的是:


学生证表


学生证号 学生证办理时间

2008 2010年9月1号

2009 2010年9月2号 


借书证表


借书证号 借书证办理时间

201001  2010年10月1号

201011  2011年10月1号


例3,订单表订单编号和商品编号为联合主键


订单编号 商品编号 商品名称 数量 单位 价格 客户 所属单位 联系方式

001 1 挖掘机 1 台 1200000¥ 张三 上海玖智 020-1234567

001 2 冲击钻 8 把 230¥     张三 上海玖智 020-1234567

002 3 铲车   2 辆 980000¥  李四 北京公司 010-1234567

这样就产生一个问题:这个表中是以订单编号和商品编号做为联合主键。这样在该表中商品名称、单位、商品价格等信息不与该表的主键相关,而仅仅是与商品编号相关。因此在这里违反了2NF的设计原则。而若是把这个订单信息表进行拆分,把商品信息分离到另外一个表中,把订单项目表也分离到另外一个表中,就很是完美了。以下所示:


订单信息表


订单编号 客户 所属单位 联系方式

001 张三 上海玖智 020-1234567

002 李四 北京公司 010-1234567


订单项目表


订单编号 商品编号 数量

001 1 1

001 2 8

002 3 2


商品信息表


商品编号 商品名称 单位 商品价格

1 挖掘机 台 1200000¥

2 冲击钻 个 230¥

3 铲车 辆 980000¥



3NF:非主键字段不能相互依赖


首先是 2NF,另外非主键列必须直接依赖于主键,不能存在传递依赖。即不能存在:非主键列 A 依赖于非主键列 B,非主键列 B 依赖于主键的状况。 通俗解释:任意一个字段都只依赖表中的同一个字段。


例1,家庭成员表


户主 儿子 女儿 女儿的小熊 女儿的海绵宝宝

Jack Tom  Lucy  Bear       spongebob

Jobs july Lily  Bear2      spongebob2

以上的表就不符合,第三范式:其中 儿子 女儿 等非主键列都彻底依赖于主键(户主),因此符合 2NF,不过问题是 女儿的小熊 女儿的海绵宝宝 直接依赖的是 女儿字段 (非主键列),而不是直接依赖于主键,它经过传递才依赖于主键,因此不符合 3NF。 因此变动为正确的是:


户主信息表


户主 儿子 女儿

Jack Tom  Lucy

Josb  July  Lily


女儿信息表


女儿 女儿的小熊 女儿的海绵宝宝

Lucy  Bear       spongebob

Lily  Bear2      spongebob2


例2,订单表(主键是OrderID)


OrderID OrderDate CustomerID CustomerName CustomerAddr CustomerCity

101  2011年 100 xx联合公司 中央大街100号 纽约

102  2012年 100 xx联合公司 中央大街100号 纽约

103  2014年 200 yy联合公司 白宫          纽约

以上的表就不符合,第三范式:其中 OrderDate,CustomerID等非主键列都彻底依赖于主键(OrderID),因此符合 2NF,不过问题是 CustomerName,CustomerAddr,CustomerCity 直接依赖的是 CustomerID(非主键列),而不是直接依赖于主键,它是经过传递才依赖于主键,因此不符合 3NF。 因此变动为正确的是:


订单表


OrderID OrderDate CustomerID

101  2011年 100

102  2012年 100

103  2014年 200


客户信息表


CustomerID CustomerName CustomerAddr CustomerCity

100 xx联合公司 中央大街100号 纽约

200 yy联合公司 白宫          纽约


例3,学生信息表(主键是学号)


学号 姓名  所在系 系名称 系地址 

101  小明  001 数学系 1号楼

102  小叶  002 文学系 5号楼

103  小炫  003 物理系 6号楼

以上的表就不符合,第三范式:其中学号,姓名,所在系等非主键列都彻底依赖于主键(学号),因此符合 2NF,不过问题是系名称,系地址直接依赖的是所在系(非主键列),而不是直接依赖于主键,它是经过传递才依赖于主键,因此不符合 3NF。 因此变动为正确的是:


学生表


学号 姓名  所在系

101  小明  001 

102  小叶  002 

103  小炫  003


院系信息表


系编号 系名称 系地址 

001 数学系 1号楼

002 文学系 5号楼

003 物理系 6号楼


第二范式(2NF)和第三范式(3NF)的概念很容易混淆,区分它们的关键点在于,2NF:非主键列是否彻底依赖于主键,仍是依赖于主键的一部分;3NF:非主键列是直接依赖于主键,仍是直接依赖于非主键列。


经过对每一个范式的定义介绍,加上几个在实践中的反例进行讲解,可在必定程度上加快理论的理解,缩短理论和实践之间的距离,可快速上手3范式在开发中的应用。

相关文章
相关标签/搜索