前言:
在使用mysql中对表的设计,我们需要遵循三大范式。
设计关系型数据库时,遵从不同的规范和要求,设计出合理的关系型数据库,这些不同的规范和要求称为不同的范式。各种范式呈递次规范,越高的范式数据库冗余越小。
若要遵循后面的范式必须遵循之前的范式。1NF<2NF<3NF<...>
注意:对于这些范式,知识来源于网络+自己总结。
范式分类:
目前关系型数据库有六种范式
第一范式(1NF)
第二范式(2NF)
第三范式(3NF)
巴斯-科徳范式(BCNF)
第四范式(4NF)
第五范式(5NF)
第一范式(1NF):
每一列都是不可分割的原子数据项(有点抽象),那么什么是原子不可分割的呢?
用excel定义一张表(注意红色部分)一个列(系)又被分为了 多个列(系名、系主任),很明显不符合第一范式要求中的数据列是不可再分的规范。
如何才能符合第一范式呢(如下)?这才是我们实际上在对表的正确定义。也就是说关系型数据库(mysql)自动遵循了第一范式。目前为止我都没见过mysql可以建立复合列。
第一范式有哪些问题呢?数据冗余严重,拿张三说事(罗教授有没有朋友知道的)姓名、系名、系主任字段冗余是不是特别严重?
数据添加存在问题,若我们在第一范式基础上添加一个系信息(系名、系主任),如红色部分,显得特别不合理。
数据删除存在问题,删除张三的数据信息,同样也会将系名、系主任信息删除掉。
了解了第一范式的问题后,如何进行解决了?就需要第二范式和第三范式。
第二范式(2NF):
在满足第一范式的基础上,非码属性必须完全依赖于码,(在1NF基础上消除非主属性对主码的部分函数依赖)
要想学习第二、三范式需要了解几个概念。
函数依赖:A..>B,如果通过A属性(属性组)的值,可以确定唯一B的属性值,那么则称B依赖于A。
例如:id>姓名,id称为A,姓名称为B,结合上面的那句话,说明姓名依赖于id。
还有一个属性组的概念,例如:通过id确定一个的分数,是无法做到的,但是(id+课程名称)>分数,则可以确定一个的分数。
完全函数依赖:A..>B,如果A是一个属性组,则B属性值的确定需要依赖于A属性组中的所有的属性值。
例如:id和课程名称可以确定一个分数,但是id和姓名、系名等其他字段都不能确定一个分数,那么分数就完全依赖于 id和课程名称。
部分函数依赖:有了完全依赖就肯定有部分函数依赖,如果A是一个属性组,则B属性值的确立只需要依赖于A属性组的某一些值即可。
例如:id 可以确认一个姓名,id+课程名称同样也可以确定一个姓名。两种关系,只要其中一种符合就行了,这就是部分函数依赖。
传递函数概念:A..>B ,B..>C,如果通过A属性(属性组)的值,可以确定唯一B的属性值,再通过B属性(属性组)的值可以确定唯一C的属性值,则C传递函数依赖于A。
例如:id(A) 可以确定 系名(B),系名(B)又可以确定系主任(C)。
码:如果在一张表中,一个属性值或属性组,被其他所有属性所完全依赖,则称为这个属性或属性组为该表的码。
例如:通过id能确定姓名、姓名又确定系名,系统再确定系主任,但是id无法确定分数。若要确定分数需要(id+课程名称),在该表中,id和课程名称被称为该表的码。
将到这里明白了第一范式的问题就是减少冗余,那么第二范式又该怎么解决呢? 将原来的表拆分出去(如下)。
这就是第二范式,消除A>B的依赖,减少冗余数据
第三范式(3NF):
在2NF基础上,任何非主属性不依赖于其他非主属性(在2NF基础上消除传递依赖)
2NF只是减少了部分依赖,但依然存在传递依赖(再看看传递函数概念)
传递函数概念:A..>B ,B..>C,如果通过A属性(属性组)的值,可以确定唯一B的属性值,再通过B属性(属性组)的值可以确定唯一C的属性值,则C传递函数依赖于A。
例如:id(A) 可以确定 系名(B),系名(B)又可以确定系主任(C)。
第三范式就是需要消除传递依赖:如上(学生表)中的系名,系主任,不能应该和学生挂钩。于是又做了一次拆分,减少传递依赖。
反第三范式:
虽然第三范式减少了数据冗余问题,也降低了表与表之间的耦合度,但并不是没有冗余的表才是最好的,因为关联查询在一定的情况下还是有部分的性能消耗的,为了使数据查询效率更高,在合理的范围内定义一些合理冗余数据。
总结:
mysql三大范式,说简单点就是减少耦合度,减少数据的冗余,学费(会)拆分。
巴斯-科徳范式(BCNF):
第四范式(4NF):
第五范式(5NF):
剩下三个有机会去补充