数据库——范式

141 阅读3分钟

函数依赖

记 A->B 表示 A 函数决定 B,也可以说 B 函数依赖于 A。

对于 A->B,如果能找到 A 的真子集 A',使得 A'-> B,那么 A->B 就是部分函数依赖,

比如:(学号,学生姓名)-> 院系

​ 但也可以直接:学号 -> 院系


否则就是完全函数依赖。

比如:(学号,课程号)-> 成绩

​ 不可拆开


另一种解释:对于(A,B,C)

有(A,B)->C,且C不能单独通过A或B得到,则该依赖为完全函数依赖。

有(A,B)->C,且C可以单独通过A或B得到,则该依赖为部分函数依赖。(会造成冗余)

有 A->B,B->C,则 A->C 是一个传递函数依赖。(会造成冗余)





异常

以下的学生课程关系中,{学号, 课程号} 为键码,有如下函数依赖:

学号 -> 学生姓名,院系

院系 -> 院长姓名

课程号 -> 课程名

(学号,课程号) -> 成绩

学号学生姓名院系院长姓名课程号课程名成绩
学生1学生A学院1院长A课程1课程A90
学生2学生B学院2院长B课程1课程A80
学生2学生B学院2院长B课程2课程B100
学生3学生C学院3院长C课程2课程B95

不符合范式的关系,会产生很多异常,主要有以下四种异常:

  • 冗余数据:例如 学生B 出现了两次。
  • 修改异常:修改学生B 一条记录中的某个信息,但另一条记录中相同的位置却没被修改。
  • 删除异常:删除学生B 一条记录中的某个信息,那么该条记录中的其他信息也会丢失。
  • 插入异常:例如想要插入一个学生的信息,如果这个学生还没选课,那么就无法插入。




范式

范式是为了消除重复数据减少冗余数据,让磁盘空间得到更有效利用的一种标准。

高级别范式的满足低级别的范式,比如2NF一定满足1NF。


1. 第一范式 (1NF)

属性不可分,均为简单属性。但四种异常均无法解决。究其原因是其中存在各种各样的函数依赖关系。

例子中的关系就是一个1NF。



2. 第二范式 (2NF)

满足1NF,并且每个非主属性完全函数依赖于键码。

可以通过分解来满足。

分解前

{学号, 课程号} 为键码。有如下函数依赖:

学号 -> 学生姓名,院系

院系 -> 院长姓名

课程号 -> 课程名

(学号,课程号) -> 成绩

  • 成绩完全依赖于键码,它没有任何冗余数据,每个学生的每门课都有特定的成绩。

  • 学生姓名院系课程名部分依赖于键码,当一个学生选修了多门课时,这些数据就会出现多次,造成大量冗余数据。

  • 院长姓名传递依赖于键码。 (2NF不考虑)


分解后

关系1

学号-> 学生姓名, 院系

院系-> 院长姓名


关系-2

学号, 课程号-> 成绩


关系-3

课程号 -> 课程名



3. 第三范式 (3NF)

满足1NF,并且非主属性不传递函数依赖于键码。

上面的 关系1 中存在以下传递函数依赖:

学号-> 院系-> 院长姓名

可以进行以下分解:

关系-11

学号-> 学生姓名, 院系


关系-12

院系-> 院长姓名





背诵版

对象拆分的好,基本上就满足三大范式了。

  • 第一范式,字段不可拆分,原子性
  • 第二范式,联合主键情况,字段都应与主键有关联。如成绩表,主键学生id,学科id,不应该出现学生班级信息之类的字段。
  • 第三范式,表不包含多余属性,学生属性属于学生,班级属性属于班级。