数据库三大范式,我之前是知道的,但是内容比较文绉绉,初学的时候不容易把握其根本。
首先是第一范式:
有主键,且数据库表的每一列都是不可分割的原子数据项。也可以理解为:无重复的列。
其实这句话的本质是控制字段的颗粒度(也许不该用这个词)。这个地方的无重复和不可分割是什么意思呢?其实是这样的。首先如果有两个字段,一个叫籍贯,一个叫家乡,是不是就有点蠢?(这个地方不考虑其区别的话)。
对重复的第一层理解是有两个字段其实是描述同样的东西,如果表格这么设计了,势必会导致数据的冗余。
第二层理解是,字段也许不是完全一样,但是有部分重叠。有两个字段,都包含部分相同的信息。这样依然会导致冗余。对于这种情况,就要分割。把重复的地方去掉一份,使数据最终都只有一份拷贝。
总的来说,第一范式是控制字段的描述,尽可能让数据不要在一个字段出现又在另外一个字段出现。
然后是第二范式:
要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性。这其实也是为冗余性服务的。
举个例子,假如有个表,名字叫学生表。主键有两个:班级和编号。也就是说我要明确是一班的1号学生才能唯一地确定学生。在这种情况下,如果表中多了一个字段,叫班级地址,这就不满足第二范式,就要把这个信息分离出去形成第二个表。
先解释为什么不满足第二范式。第二范式说的是完全依赖,也就是说必须要有班级和编号才能唯一确定每一个字段的信息。可是班级地址不需要编号这个主键。事实上你只要告诉我是多少班,我就知道这个班的地址,而你告诉我这个人的编号,完全没有意义。这也就是部分依赖,没有完全使用主键的全部信息,只需要一部分就可以推出依赖关系。
那么这到底会引发什么呢?试想如果强行不满足第二范式。这个学生表里面就有了班级地址这一栏。那么,在这个表里面,可能很多学生都是一班的,张三李四王二。他们都傻乎乎地储存了“第一教学楼三楼A107”这么个信息,是不是就导致了冗余?只需要一份拷贝的东西结果每个人都储存了。这里正确的做法是删除班级地址这一项。再新建第二张表:班级-->班级地址。其中班级是主键。这样每一个班的地址都只有一份拷贝。学生表中只需要储存班级就可以来这个表找到地址信息。
接着是第三范式:
任何非主属性不依赖于其它非主属性。
这又是什么意思呢?这就是说一个表里面只能有一个主键,有它就可以唯一确定字段信息。不能有字段依赖于不是主键的字段。再举个例子,公司有个人信息表。里面有ID,这就是找个表的主键,唯一确定一个员工。表后面加上了部门编号这个字段。这里没有问题。可是如果还有字段叫“部门名称”,“部门简介”。这就不满足第三范式了。因为部门名称和部门简介都是依赖于部门编号的,而部门编号不是这个表的主键。
那么,这又会导致什么问题呢?其实还是冗杂。也许有很多员工是“技术部”的,每一个员工的个人信息里面都储存了“技术部”“部门简介:。。。。。。。”
这就导致了和上面说的差不多的情况。同样的信息有很多份拷贝。
所以应该做的是把这部分信息独立出来变成一个新的表,每个员工信息表只需要保留部门编号这个字段就可以了。然后在需要的时候再去部门表根据部门编号找相关信息。
其实,一个比较深入的理解是第二范式和第三范式是同一个性质的延伸:一个表里面只能有一个映射关系。
这句话是怎么理解呢?我这里说的映射是指从主键到字段的唯一对于关系。对于第二范式,因为存在部分依赖,所以有的映射和“主键-->字段”这个映射不同(尽管看上去像是父子关系,但其实不同)。第三范式则是直接在一个表里面有不同的映射(依赖)。所以,但一个表里面存在两种映射的时候,就不满住这个性质。
而一个表确实只应该有一种映射,存在别的映射可以理解为把多个表结合在了一起。所以普遍解决方法是分表。而它产生的问题则是导致数据的冗余(一份数据多份拷贝)。
以上是我结合别人文章的理解。