第九章:第19节 MySQL基础篇——数据库设计3范式(3NF)

更新于:2017-07-31 11:47:58

MySQL数据库它是关系型数据库,关系型数据库是有多张表组成,表里有很多字段,表与表之间可通过某个(些)字段建立联系。所以说,很多数据表不是独立存在的。


很多时候是这样的情况:网站页面显示一篇文章,不仅显示文章内容、标题、发表时间,还要显示所属专栏、作者,或者作者的一些详细信息(名字、哪里人、简介什么的)。通常我们设计数据库时,肯定不会把这么多信息字段写在一个表里,最好的设计方案分成三个表:文章表、栏目表、作者表。


道理很简单:

一个栏目下是不是可以有很多文章,一个作者是不是也可以有很多文章。

我们在设计文章表时,不要在每行记录下多增加好几个字段描述栏目的一些信息,一些作者的信息(这样会出现大量的重复记录,其实和PHP一样,不要重复的造轮子,在PHP中出现重复的代码把它们定义成函数),只需要增加两个整数型字段关联栏目表的主键ID、作者表的主键ID。


图示一:


1.png


上面的图是一个文章表的数据,字段依次表示的:文章ID、文章标题、内容、发表时间、作者名、作者年龄、学历、兴趣、地址、注册时间。


有没有发现有关作者的信息描述,出现了大量的重复数据,所以说这样设计数据库不好,应该分开:


文章表:

1.png

“author”字段记录的是作者表的主键ID


作者表:

1.png


这两张表通过文章表“author”字段作者表ID字段之间建立起了关联。


这样设计有很多好处,比如说:某个作者的信息有所变动,只要改一下就可以了,图示一的表那就可能需要改很多很多。


如果文章需要归“栏目”,和关联“作者”一样,设计一个栏目表,在文章表增加一个整数型字段记录栏目表的主键ID,这样就可以建立起关联了。


上面楠神介绍的是数据表最常见的设计方式。下面系统地看下数据表的设计三范式。



数据库(数据表)的设计思想介绍


所谓数据库的设计,通常就是指数据表的设计,也就是表结构的设计,以及需要哪些表。这种设计基本都是由每一个具体的项目功能来决定的。我们需要确定一个项目会用到哪些“现实数据”,以及为实现这些功能还需要创建(或定义)哪些数据才可以到达功能目标。这也就是构成了一个项目的数据库设计工作。数据库设计工作通常都是一个项目在技术层面最为重要和基础的工作。数据库设计没定下来,后续的开发工作很难进行。数据库设计得不好,后续的开发工作就可能问题重重。


数据库设计原则——也称为数据库设计三范式(3NF)


范式,就是规范,就是指设计数据库需要(应该)遵循的原则。

每个范式,都是用来规定某种结构或数据要求——后一范式都是在前一范式已经满足的情况用来“加强要求”


第一范式(1NF),原子性


原子性:

存储的数据应该具有“不可再分性”。

不良做法示例:


d6ca7bcb0a46f21fd656b015f7246b600c33ae12.jpg


可见,其违反了原则性范式:学生字段的数据存储了多个可分的数据。

修改后为:


d6ca7bcb0a46f21fd656b015f7246b600c33ae12.jpg


第二范式(2NF)唯一性

需要实现每一行数据具有唯一可区分的特性,并不能有部分依赖关系

通常,给一个表加主键(也是推荐做法),就可以做到“唯一可区分”。

但主键有这样情况:

设定一个字段为主键:此时,表示该一个字段的值就可以明确确定一行数据。

设定多个字段为主键:表示只有这多个字段的值都确定后才能确定一行数据。此时也称为“联合主键”

什么叫依赖:

如果确定一个表中的某个数据(A),则就可以确定该表中的其他另一个数据(B),则我们说:B依赖于A

实际上,一个表只要有主键,则其他非主键一定是依赖于主键的。

 

什么叫“部分依赖”:

如果确定一个表中的某个数据组合(AB),则就可以确定该表中的其他另一个数据(C),则我们说:C依赖于(AB)(此时AB通常就是做出主键)。

但:如果某个数据D,它只依赖于数据A,或者说,A一确定,则D也可以确定,此时我们就称为“数据D部分依赖于数据A——可见部分依赖是指某个非主键字段,依赖于联合主键字段的其中部分字段

 

不良做法:

d6ca7bcb0a46f21fd656b015f7246b600c33ae12.jpg

修正之后:

d6ca7bcb0a46f21fd656b015f7246b600c33ae12.jpg


备注说明:三范式介绍楠神摘自其他地方,根据楠神本身的习惯,我设计一个表都会加上一个主键ID的(我不喜欢创建联合主键),像成绩表里楠神一般会把学生ID、课程ID加上一个唯一索引。


第三范式(3NF):独立性,消除传递依赖

在一个具有主键的表中,假设主键为A,其必然其他非主键都依赖于该主键,比如:B依赖于AC依赖于AD依赖于A。。。。。。

但同时:如果该表中的某个字段B的值一确定,就能够确定另一个字段的值C,则我们称为C依赖于B

那么,就出现了:

C依赖BB依赖A——这就是传递依赖。

则消除该传递依赖的的通常做法,就是将C依赖于B的数据,分离到另一个表中。

 

不良例子:

d6ca7bcb0a46f21fd656b015f7246b600c33ae12.jpg

修正之后:

d6ca7bcb0a46f21fd656b015f7246b600c33ae12.jpg


备注说明:楠神一开始举得例子文章表、作者表的设计符合了表设计的独立性。


最后的总结

通常,在实践中,满足3范式只要做到“一个表只存一种数据基本就可以实现。

 

另外,范式不是绝对要求,有时候我们为了数据的使用方便,还会(需要)故意违反范式。


比如平台不能更改作者名字,那文章表可以单独增加一个字段存“作者名字”,那获取数据的时候可能会减少连表查询的次数,提高效率。


连表查询就是连接查询,下节开始介绍。