数据库范式:

  第1范式:属性必须是原子的,不可分的。从实体的角度看是实体属性的类型只能是基本数据类型,不能是复合数据类型。这一条对于关系数据库来说很容易满足,但对于面向对象数据库来说不一定了。而且需要特别注意的是数据库范式的考察必须与具体的需求相关,也是属性的原子性不是的,而是相对于需求的。比如对于学生表(学号,姓名,学校),对于学校这个属性而言,如果我们不需要更进一步的考察,那么学校属性是原子的,如果需要进一步分解学校这个属性,比如为学校(学校编号,校名,成立日期),那么学校属性是非原子的。

  第2范式:非主属性a不能部分依赖于侯选键R。如果非主属性a部分依赖于侯选键R,则说明这个非主属性和其依赖的主属性集合A(A是R的真子集)在这张表中存在行上的数据重复。比如用户角色关系表(用户ID,角色ID,角色名称),其中(用户ID,角色ID)为侯选键,角色名称依赖于角色ID,是一种部分依赖,这种设计有4个问题:

  1)是数据存储冗余:在这张表中角色ID和角色姓名存在大量的存储冗余(比如一个角色对应N个用户,则角色名称需要重复存N次).

  2)是更新异常:如果某一行的角色姓名被修改,必须同时更新所有对应角色ID的角色姓名,不能仅仅只更新侯选键所在的行;

  3)插入异常:如果新增加一个角色,由于没有选课,则无法录入;

  4)删除异常:同样的,如果用户角色关系删除后可能导致角色信息业被删除;

  为了避免上述问题,则可以增加一张表2(角色ID,角色姓名),将用户角色关系表改为(用户ID,角色ID),可以消除用户角色关系表中的部分依赖,从而减少数据冗余和异常操作问题。虽然增加一个主键列关系ID,可以消除这种部分依赖,但并不能解决问题的实质:存储冗余和操作异常。

  第3范式:在第二范式的基础上,属性不能依赖于其它非主属性。如果一个属性依赖于其它非主属性,一样会存在范式2中所说的几个问题,解决办法同范式2。

  BCNF(鲍依斯-科得范式):若关系模式是第一范式,且每个属性都不传递依赖于关系模式的候选键.很容易证明该范式满足第2范式,因为如果有非主属性a部分依赖于侯选键R1(候选键R),则很容易得出R->R1->a,即a传递依赖于R,与定义不符合。

  同样也可以证明BCNF满足第3范式,因为一个属性如果依赖于其它非主属性,则必然传递依赖于其候选键。其实BCNF表达的是一个关系模式中,任何属性都只能直接依赖于候选键,从消除了主属性对候选键的传递依赖,在第3范式并没有限制主属性不能能依赖于其它主属性。

  从上面的范式可以看出,提出范式的根本目的是消除冗余和各种操作异常。但在实际中,并不能会完全满足上述范式,一是出于性能的考虑,通过冗余一定的数据来换取性能上优势或者程序编写上的便利。这种例子比较多,但需要注意的是,冗余的这些数据一般是不需要改动,或者改动非常少的,或者一致性要求可以忽略,而且不会带来操作异常中的插入和删除异常问题,比如订单明细表(订单号,明细序号,产品编码,产品名称)和产品信息表(产品编码,产品名称)还是会有两张表,这种冗余不会产生插入和删除异常,而且一般产品信息表中的产品名称修改的可能性比较小,订单明细中的产品名称不会修改,更新异常不会太严重,因此这种冗余是可以的,影响非常小;另外一种情况是根据业务必须冗余的,非常典型的是带有法律意义的有价证券的设计上,比如合同如果涉及到产品,为了电子版和纸质版一致,那么产品名称和产品ID都需要保存(当然,在产品一旦使用不能修改名称的情况下,这种保存没必要,这里只是为了举例).还有一种情况是看起来是不符合范式,但实际上并不违背范式,这主要是一些模板性基础表和业务表之间的冗余。  (以上举例中的表设计仅仅是为了举例,不是必然的,在不同的要求下,情况会不一样)。