sql范式

数据库范式

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

目前关系型数据库一共有6种范式,,由低到高分别为:

  1. 1NF(第一范式)
  2. 2NF(第二范式)
  3. 3NF(第三范式)
  4. BCNF(巴斯-科德范式)
  5. 4NF(第四范式)
  6. 5NF(第五范式,也叫完美范式)

数据库范式的设计越高阶,冗余度就越低,同时高阶的范式一定会满足低阶的要求。

数据库表中键的定义

  • 超键:能唯一标识的属性集

  • 候选键:如果超键中不包含多余的属性,那么这个键就是超键

  • 主键:用户可以从候选键中选择一个键作为主键

  • 外键:如果R1数据表中某属性集不是R1的主键,而是另一个表R2的主键,那么这个键就是R1的主键

  • 主属性:包含任一候选键的属性成为主属性

  • 非主属性:与主属性相对,不包含任何一个候选键的属性

第一范式指的是数据表中任何属性都是原子性的,不可再分。几乎所有关系型数据库都满足第一范式的要求。

第二范式指的是数据表的非主属性都要和这个数据表的候选键有完全依赖。以球员表player_game表为例,包含球员编号,姓名,年龄,比赛编号,比赛时间和比赛场地等属性,这里的候选键和主键分别为(球员编号和比赛编号)。但是这个数据表设计并不满足第二范式,因为还存在以下对应关系:

1
2
(球员编号)--> (姓名,年龄)
(比赛编号) --> (比赛时间,比赛场地)

这样会产生以下问题:

  1. 数据冗余:如果一个球员可以参加n场比赛,那么球员的姓名和年龄就重复了n-1次。一个比赛可能有m个球员参加,比赛时间和场地就重复了m-1次
  2. 插入异常:我们想要添加一场新的比赛,但是这时还没确定参加的球员都有谁,那么久没法插入
  3. 删除异常:比如想要删除某个球员编号,如果没有单独保存比赛表时,就会把比赛信息也删除掉
  4. 更新异常:如果想要调整某个比赛时间,那么数据表中所有时间都要调整

为避免以上情况,可以将一张表拆分为3张表。球员player表包含球员编号,年龄,姓名;比赛game表包含比赛编号,比赛时间和比赛场地等属性;球员关系player_game表包含球员编号,比赛编号,比赛得分等属性

第三范式:对任何非主属性都不传递依赖于候选键。

以球员player表为例,这张表包含球员编号,姓名,球队名称,球队主教练。球员编号决定了球队名称,球队名称决定了球队主教练,那么非主属性球队主教练就依赖于候选键球员编号。需要将player表拆分为下面这样:

球员表包含球员编号,姓名和球队名称;球队表包含球队名称和球队主教练。

当然,也不一定是范式越高就越好,越高阶以为这冗余越少,同时数据表也越多,搜索的时间也越大。实际工作中往往根据实际情况适当采用反范式,以时间换取空间的做法,容忍适当的冗余。

仓库名 管理员 物品名 数量
北京仓 张三 iPhone XR 10
北京仓 张三 iPhone 7 20
上海仓 李四 iPhone 8 30
上海仓 李四 iPhone X 40

在上表中,一个仓库只有一个管理员,同时一个管理员也管理者一个仓库。这样候选键为(仓库名,物品名)和(管理员,物品名),然后我们从中选取一个候选键作为主键。按照以上理论梳理,此表满足了1NF,2NF,3NF规范,但是同样存在以下问题:

  1. 增加一个仓库,但是没有存放任何物品,根据数据完整性的要求,主键不能有空值,因此会出现插入异常
  2. 仓库管理员更换之后,会修改多条记录
  3. 仓库物品卖空后,仓库名称和管理员都会随之删除掉

由此引入BCNF(巴斯-科德范式):它在3NF的基础上消除了主属性对候选键的部分依赖或者传递依赖关系

按照BCNF要求,我们需要将上表拆分为两个表:

  • 仓库表:(仓库名,管理员)
  • 库存表:(仓库名,物品名,数量)
-------------本文结束感谢您的阅读-------------