范式设计:数据表的范式有哪些,3NF指的是什么?


很多时候,当数据库运行一段时间后,我们才发现数据表设计的有问题。重新调整数据表的结构,就需要做数据迁移,还有可能影响程序的业务逻辑,以及网站的正常访问。所以在开始设置数据库的时候,我们就需要重视数据表的设计

准备知识

函数依赖

范式设计:数据表的范式有哪些,3NF指的是什么?
解释:∀ -->代表任意的 。
依赖:R(U)是 自变量集U上的关系集合 [函数集合]。 X,Y属于自变量集合,r是R(U)关系集合中的任意一个关系 [函数]。对于任意的t和s 属于r,若t[X] = s[X] 则 t[Y] = s[Y] ,那么称X函数决定Y,或者Y函数依赖于X,记作X–>Y
也就是一个或者一组属性的值可以决定其他属性的值,候选键可以做到

部分函数依赖

设X,Y是关系R的两个属性集合,存在X->Y,若X’是X的真子集,存在X’->Y,则称Y部分依赖于X
例子:学生信息表R中(学号,身份证号,姓名),学号属性的取值是唯一的, 在R关系中,(学号,身份证号)->(姓名),(学号)->(姓名),(身份证号)->(姓名);所以姓名部分依赖于(学号,身份证号)

完全函数依赖

设X,Y是关系R的两个属性集合, X’是X的真子集,存在X->Y,但对于每一个X’ 都有X’!->Y,则称Y完全依赖于X
例子:学生信息表R(学生,班级,姓名),假设不同的班级学号有相同的,班级内学号不能相同,在R关系中,(学号,班级)->(姓名); 但是(学号)->(姓名)不成立,(班级)->(姓名)不成立,所以姓名完全依赖于(学号,班级)

传递函数依赖

设X,Y,Z是关系R中互不相同的属性集合,存在X->Y (Y!->X),Y->Z,则称Z传递函数依赖于X
例子:在关系R(学号,宿舍,费用)中,(学号)->(宿舍), (宿舍)!->学号, (宿舍) ->(费用) ,(费用)!->(宿舍) ,所以符合传递函数的要求


什么是范式

范式是数据表设计的基本原则,我们在设计关系型数据库模型的时候,需要对关系内部各个属性之间联系的合理化程度进行定义,这就有了不同等级的规范要求,这些规范要求被称为范式(NF)。可以吧范式理解为,一张数据表的设计结构需要满足某种设计标准的级别。

范式的级别

目前关系型数据库一共有6种范式,按照范式级别,从低到高分别是

  • 1NF(第一范式)
  • 2NF(第二范式)
  • 3NF(第三范式)
  • BCNF(巴斯 - 科德范式)
  • 4NF(第四范式)
  • 5NF(第五范式,又叫做完美范式)
    数据库的范式设计越高阶,冗余度就越低。高阶范式一定符合低阶范式的要求
    一般来说,数据表的设计应尽量满足3NF。但不绝对,有时候为了提高某种查询性能,我们还需要破坏范式规则,也就是反规范化
    范式设计:数据表的范式有哪些,3NF指的是什么?

范式定义的元素

范式的定义会使用到主键和候选键(因为主键和候选键可以唯一标识元组[元组就是数据])。
数据库中的键(Key)由一个或者多个属性组成。通常,我们也将候选键称为码,把主键也称为主码

例如 一个表有(id,name,sex,age)字段

  • 超键:能唯一标识元组的属性集叫做超键 [唯一标识数据,比如(id,name,sex,age)是超键,(id,name,sex)是超键,可以理解为所有能有效区分数据记录的属性(列)的集合,可以包含一些对区分数据记录无用的属性集,超键,超的主要意义是多于]
  • 候选键:如果超键不包含多余属性,那么这个超键就是候选键 [唯一标识数据,不包含多于属性的超键称为候选键,也就是在候选键中,若要再删除属性,就不能唯一标识元组了]
  • 主键:用户可以从候选键中选择一个作为主键[主键可以是单一字段也可以是字段集合]
  • 外键:如果数据表R1中的某属性集不是R1的主键,而是另外一个数据表R2的主键,那么这个属性集就是数据表R1的外键
    因为键可能是由多个属性组成的,针对单个属性,可以用主属性和非主属性
  • 主属性:包含在任一候选键的属性称为主属性
  • 非主属性:与主属性相对,指的是不包含在任何一个候选键中的属性

例子

球员表(player)

球员编号 姓名 身份证号 球队编号
#123 张珊 14233219942381249 #1

球队表(team)

球队编号 主教练 球队所在地
#1 王五 北京

对于球员表
超键:球员编号或者身份证编号的任意组合 (球员编号)、(球员编号,姓名)、(身份证号,年龄)
候选键:是最小的超键 (球员编号)、(身份证号)
主键:就是从候选键中选择一个 (球员编号)
外键:(球员编号)
主属性:(球员编号)、(身份证号)
其他属性:(姓名)、(年龄)、(球队编号)


从1NF到3NF

1NF

1NF指的是数据库表中的任何属性都是原子性的,不可再分
理解:我们在设计某个字段的时候,对于字段X来说,就不能把字段X拆分成字段X-1和字段X-2。

2NF

2NF指的是数据表里面的非主属性都要和这个数据表的候选键[所有的候选键]有完全依赖的关系。
理解:比如一张球员比赛表,字段 球员编号、姓名、年龄、比赛编号、比赛时间、比赛场地等属性。
候选键和主键为(球员编号,比赛编号),我们可以通过候选键来决定如下的关系,(球员编号,比赛编号)–>(姓名、年龄、比赛时间、比赛场地、得分)
但是这个不满足第二范式,因为字段之间还存在如下关系:
(球员编号)—>(姓名,年龄)
(比赛编号)—>(比赛时间,比赛场地)
也就是说候选键中某个字段决定了非主属性。这样会产生以下问题

  1. 数据冗余:如果一个球员可以参加m场比赛没那么球员的姓名和年龄就重复了m-1次。一个比赛也可能会有n个球员参加,比赛的时间和地点就重复了n-1次
  2. 插入异常:如果想要添加一场新的比赛,但是没有确定参加球员都有谁,那么就没法插入
  3. 删除异常:如果我们要删除某个球员编号,如果没有单独保存比赛表的话,就会同时把比赛信息删除掉
  4. 更新异常:如果我们调整了某个比赛的时间,那么数据表中所有这个比赛的时间都需要调整,否则就会出现一场比赛时间不同的情况
    某种程度上,2NF是对1NF原子性的升级,1NF告诉我们字段属性需要是原子性的,而2NF告诉我们一张表就是一个独立的对象

3NF

3NF在满足2NF的同时,对任何非主属性都不传递依赖于候选键
也就是不存在非主属性A依赖于非主属性B,非主属性B依赖于候选键的情况
理解:比如球员表, 表字段(球员编号,姓名,球队名称,球队主教练)
范式设计:数据表的范式有哪些,3NF指的是什么?
可以看出球员编号决定了球队名称。同时球队名称决定了球队主教练,非主属性球队教练就会传递依赖于球员编号,因此不符合3NF的要求
如果要符合3NF,可以把数据表拆分成下面的, 球员表(球员编号,姓名,球队名称) 球队表(球队名称,球队主教练)

总结

1NF需要保证表中每个属性都保持原子性;2NF需要保证表中的非主属性与候选键完全依赖;3NF需要保证表中的非主属性与候选键不存在传递依赖

范式这是给出了设计的标准,实际上设计数据表的时候,未必要符合这些原则。一方面是因为这些范式本身存在一些问题,可能会带来插入,更新,删除等的异常情况。另一方面可能降低查询的效率,因为范式等级越高,设计出来的数据表就越多,进行数据查询的的时候就可能需要关联多张表,从而影响查询效率