该文章,GitHub已收录,欢迎老板们前来Star!git
GitHub地址: https://github.com/Ziphtracks/JavaLearningmanualgithub
设计关系数据库时,听从不一样的规范要求,设计出合理的关系型数据库,这些不一样的规范要求被称为不一样的范式,各类范式呈递次规范,越高的范式数据库冗余越小。数据库
范式来自英文Normal form,简称NF。要想设计—个好的关系,必须使关系知足必定的约束条件,此约束已经造成了规范,分红几个等级,一级比一级要求得严格。知足这些规范的数据库是简洁的、结构明晰的,同时,不会发生插入(insert)、删除(delete)和更新(update)操做异常。app
目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。知足最低要求的范式是第一范式(1NF)。在第一范式的基础上进一步知足更多规范要求的称为第二范式(2NF),其他范式以次类推。通常来讲,数据库只需知足第三范式(3NF)就好了。函数
第一范式强调每一列都是不可分割的原子数据项。 性能
说到原子
这个词,确定有小伙伴就先到了原子性问题,其实这么想也是没有错的。那就让我带大家去剖析一下第一范式。spa
首先,我用Excel表格模拟数据库中的表,并在表中填入了一些数据。以下:设计
当你看到这些数据的时候,是否有些数据让你感到不适?个人答案,是的。当我看到系名/系主任
这一列数据的时候感受这并不合符咱们数据库的设计理念,由于它彻底能够拆分为两个列的。其实每个人的思想中的已经有了这个范式要求的概念,只是你并不知道这个概念叫作第一范式。code
若是有的小伙伴说,这些数据都让感到不适,那我就在这里夸上你一句,你很聪明。可是请你跟紧个人思路,我会一步一步的将数据落实到范式中!orm
表1显然不遵循第一范式,那咱们就把它修改一下,让其遵循第一范式的要求。
将系名/系主任
的列拆分红了两个列系名
和系主任
后,很明显改数据已经遵循的第一范式的要求。再来看看这张表2,聪明的你是否是第一眼又发现了问题呢?
存在的问题:
- 存在很是严重的数据冗余,姓名、系名、系主任
- 添加数据问题:当在数据表中添加一个新系和系主任时,好比:在数据表中添加高主任管理化学系。你会发现添加以后,在一个数据表中就会多出来了高主任和化学系,而这两个数据并无对应哪一个学生,显然这时不合法的数据。
- 删除数据问题:若是Jack同窗毕业多年了,咱们数据表中没有必要在留Jack相关的数据了,就会想到把Jack相关的删除掉。当你在表2的表结构中删除了Jack相关数据,你会发现整个刘主任和管理系以及会计和酒店管理都消失了,难道数据表中没有这些数据就证实这个学校没有它们吗?显然这更加离谱了!
了解了只遵循第一范式带来的麻烦,咱们就须要去看一下第二范式是怎么定义的,是否能解决第一范式留下来的问题!
第二范式在1NF的基础上,非属性码的属性必须彻底依赖于主码。(在1NF基础上消除非属性码的属性对主码的部分函数依赖)
看到第二范式的概念,如今你应该是一个不懂的状态。那让我带你了解几个概念吧,这样你就会懂了!
函数依赖: A - > B,若是经过A属性(或属性组)的值能够肯定惟一B属性的值,则能够成为B依赖于A(- >符号是肯定关系)。例如:能够经过学号来肯定姓名,能够经过学号和课程来肯定该课程的分数等等
- 彻底函数依赖: A - > B,若是A是一个属性组,则B属性的肯定须要依赖A属性组中的全部属性值。例如:分数的肯定须要依赖于学号和课程,而学号和课程能够称为一个属性组。若是有学号没有课程,咱们只知道是谁的分数,而不知道是那一学科的分数。若是有课程没有学号,那咱们只知道是哪个学科的分数,而不知道是谁的分数。因此该属性组的两个值是必不可少的。这就是彻底函数依赖。
- 部分函数依赖: A - > B,若是A是一个属性组,则B属性的肯定须要依赖A属性组中的部分属性值。例如:若是一个属性组中有两个属性值,它们分别是学号和课程名称。那姓名的肯定只依赖这个属性组中的学号,于课程名称无关。简单来讲,依赖于属性组的中部分红员便可成为部分函数依赖。
- 传递函数依赖: A - > B - > C,传递函数依赖就是一个依赖的传递关系。经过肯定A来肯定B,肯定了B以后,也就能够肯定C,三者的依赖关系就是C依赖于B,B依赖于A。例如:咱们能够经过学号来肯定这位学生所在的系部,再经过系部来肯定系主任是谁。而这个三者的依赖关系就是一种传递函数依赖。
- 码: 若是在一张表中,一个属性或属性组,被其余全部属性所彻底函数依赖 ,则称这个属性(或属性组)为该表的候选码,简称码。然而码又分为主属性码和非属性码。例如:分数的肯定没有学号和课程是不行的,因此分数彻底函数依赖于课程和学号。
- 主属性码: 主属性码也叫主码,即在全部候选码挑选一个作主码,这里至关因而主键。例如:分数彻底函数依赖于课程和学号。该码属性组中的值就有课程、学号和分数,因此咱们要在三个候选码中,挑选一个作主码,那就能够挑选学号。
- 非属性码: 除主码属性组之外的属性,叫作非属性码。例如:在分数彻底函数依赖于课程和学号时,其中学号已经让咱们选为主码。那么咱们就能够肯定,除了学号之外的属性值,其余的属性值都是非属性码。也就是说在这个彻底函数依赖关系中,课程和分数是非属性码。
当咱们了解这些概念后,回过头来再看2NF的概念:在1NF的基础上,非属性码的属性必须彻底依赖于主码(在1NF基础上消除非属性码的属性对主码的部分函数依赖)
咱们还使用分数彻底函数依赖于学号和课程这个函数依赖关系。此关系中非属性码为:课程和分数,主码为学号。梳理清楚关系后,遵循在1NF基础上,非属性码的属性必须彻底依赖于主码的第二范式。就须要继续修改表结构了。遵循1NF和2NF的表结构以下:
正如你所看到的,咱们把表2根据1NF和2NF拆分红了表3和表4。这时候你再看表3,表3中的分数就彻底函数依赖于表3中的学号和课程。表4中也挑选学号作主码。虽然解决了数据冗余问题,可是仅仅这样仍是不够的,上述问题中其余的两个问题并无获得解决!
存在的问题:
- 数据删除问题
- 数据添加问题
注意: 在第二范式中存在的这两个问题,就是在第一范式中存在问题的其中两个并无获得解决。
既然第一范式和第二范式都没有解决这两个问题,那第三范式帮你解决!
第三范式在2NF基础上,消除传递依赖。
说到传递依赖,那咱们的数据表中还有哪些传递依赖呢?这时候你会发现表4中含有传递依赖的。表4中的传递依赖关系为:姓名 - > 系名 - > 系主任。该传递依赖关系为系主任传递依赖于姓名。再根据此传递依赖关系分析咱们添加和删除问题就漏洞百出了。消除传递依赖的办法仍是将表4进行拆分。拆分后的表结构以下:
当咱们把表4拆分红表5和表6时,你再来分析添加和删除问题就会有不同的结果。假设在数据表中添加高主任管理的化学系时,该数据只会添加到表6中,不会发生传递依赖而影响其余数据。那假设Jack同窗毕业了,要将Jack同窗的相关数据从表中删除,这时咱们须要删除表6中的学号3数据和表3中的学号3数据便可,它们也没有传递依赖关系,一样不会影响到其余数据。
在这里我详细讲解了数据库的三大范式,为何通常咱们只研究三大范式而不去延申至六大范式呢?在上面数据库范式概念的时候,我也有讲过。这里我还须要强调一下!
数据库六大范式,一级比一级要求得严格。各类范式呈递次规范,越高的范式数据库冗余越小。范式便是对数据库表设计的约束,约束越多,表设计就越复杂。表数据过于复杂,对于咱们后期对数据库表的维护以及扩展、删除、备份等种种操做带来了必定的难度。因此,在实际开发中咱们只须要遵循数据库前面的三大范式便可,不须要额外延申扩展。
注意: 在剖析三大范式的时候,最终版本的表结构就是表3 + 表5 + 表6
。我须要在这里说明一个问题,其实这样设计表是能够的,但并非很合理。由于咱们在建表的时候是有主键和外键约束的。这三张表中,第一列的表默认为主键,其中主键为学号还能够接收,若是主键为系名那就占用的空间变大了。在表的级联查询中会损耗性能。因此,通常咱们在设计表的时候,是须要主外键约束的,而其主外键基本是都是占用内容空间很小的数字。当你的表结构和需求知足主键递增时,则能够经过设置auto_increment
参数来完成!
这里若是不了解MySQL主外键约束的小伙伴,能够参考此文章MySQL基础来查补缺漏知识点。