数据库设计规范

范式

键和相关属性的概率

范式的定义会使用到主键和候选键,数据库中的键(Key)由一个或者多个属性组成。数据表中常用的几种键和属性的定义:

  • 超键︰能唯─标识元组的属性集叫做超键。
  • 候选键︰如果超键不包括多余的属性,那么这个超键就是候选键。
    • 主键:用户可以从候选键中选择一个作为主键。
  • 外键∶如果数据表R1中的某属性集不是R1的主键,而是另一个数据表R2的主键,那么这个属性集就是数据表R1的外键。
  • 主属性:包含在任一候选键中的属性称为主属性。
  • 非主属性:与主属性相对,指的是不包含在任何一个候选键中的属性。

通常,我们也将候选键称之为“码”,把主键也称为“主码”。因为键可能是由多个属性组成的,针对单个属性,我们还可以用主属性和非主属性来进行区分。

第一范式

第一范式主要是确保数据表中每个字段的值必须具有原子性,也就是说数据表中每个字段的值为不可再次拆分的最小数据单元。
我们在设计某个字段的时候,对于字段X来说,不能把字段X拆分成字段X-1和字段X-2。事实上,任何的DBMS都会满足第一范式的要求,不会将字段进行拆分。
举例1:
假设一家公司要存储员工的姓名和联系方式。它创建一个如下表:
image.png该表不符合1NF,因为规则说“表的每个属性必须具有原子(单个)值”lisi和zhaoliu员工的emp_mobile值违反了该规则(有两个电话)。为了使表符合1NF,我们应该有如下表数据:
image.png
距离2:
image.png
其中,user_info字段为用户信息,可以进一步拆分成更小粒度的字段,不符合数据库设计对第一范式的要求。将 user_info拆分后如下:
image.png
举例3:
属性的原子性是 主观的
image.png
在某些需求场景中表一是符合1NF的,在某些情况下又是不符合1NF的

第二范式

第二范式要求,在满足第一范式的基础上,还要满足数据表里的每一条数据记录,都是可唯一标识的。而且所有非主键字段,都必须完全依赖主键,不能只依赖主键的一部分。如果知道主键的所有属性的值,就可以检索到任何元组(行)的任何属性的任何值。(要求中的主键,其实可以拓展替换为候选键)。
举例1:
成绩表 (学号,课程号,成绩)关系中,对(学号,课程号)建立主键索引,(学号,课程号)可以决定成绩,但是学号不能决定成绩,课程号也不能决定成绩,所以(学号,课程号)→ 成绩就是 **完全依赖关系 **。
举例2:
比赛表 player_game ,里面包含球员编号、姓名、年龄、比赛编号、比赛时间和比赛场地等属性,这里候选键和主键都为(球员编号,比赛编号),我们可以通过候选键(或主键)来决定如下的关系:

(球员编号, 比赛编号) → (姓名, 年龄, 比赛时间, 比赛场地,得分)

但是上述关系并不符合第二范式,原因如下:

姓名和年龄部分依赖球员编号,并不依赖于比赛编号

(球员编号) → (姓名,年龄)

比赛时间, 比赛场地部分依赖(球员编号, 比赛编号),并不依赖于球员编号

(比赛编号) → (比赛时间, 比赛场地)

非主属性并没有完全依赖候选键,会产生什么问题呢?

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

为了避免出现上述的情况,我们可以把球员比赛表设计为下面的三张表
image.png
这样的话,每张数据表都符合第二范式,也就避免了异常情况的发生。

1NF 告诉我们字段属性需要是原子性的,而 2NF 告诉我们一张表就是一个独立的对象,一张表只表达一个意思

第三范式

第三范式是在第二范式的基础上,确保数据表中的每一个非主键字段都和主键字段直接相关,也就是说,要求数据表中的所有非主键字段不能依赖于其他非主键字段。(即,不能存在非主属性A依赖于非主属性B,非主属任B依赖于主键C的情况,即存在“A→B一C”"的决定关系)通俗地讲,该规则的意思是所有非主键属性之间不能有依赖关系,必须相互独立

这里的主键可以拓展为候选键。

举例1:
**部门信息表 **:每个部门有部门编号(dept_id)、部门名称、部门简介等信息。
员工信息表 :每个员工有员工编号、姓名、部门编号。列出部门编号后就不能再将部门名称、部门简介等与部门有关的信息再加入员工信息表中,因为部门名称,部门简介依赖于部门编号,不符合第三范式
举例2:
image.png
商品类别名称依赖于商品类别编号,不符合第三范式
修改:
image.png
举例3:
球员player表 :球员编号、姓名、球队名称和球队主教练。现在,我们把属性之间的依赖关系画出 来,如下图所示:
image.png
你能看到球员编号决定了球队名称,同时球队名称决定了球队主教练,非主属性球队主教练就会传递依赖于球员编号,因此不符合 3NF 的要求。**如果要达到 3NF 的要求,需要把数据表拆成下面这样:
image.png

小结

关于数据表的设计,有三个范式要遵循。
(1)第一范式(1NF),确保每列保持原子性
数据库的每一列都是不可分割的原子数据项,不可再分的最小数据单元,而不能是集合、数组、记录等非原子数据项。
(2)第二范式(2NF),确保每列都和主键完全依赖
尤其在复合主键的情况下,非主键部分不应该依赖于部分主键。
(3)第三范式(3NF)确保每列都和主键列直接相关,而不是间接相关
范式的优点: 数据的标准化有助于消除数据库中的数据冗余,第三范式(3NF)通常被认为在性能、扩展性和数据完整性方面达到了最好的平衡。
范式的缺点:范式的使用,可能降低查询的效率。因为范式等级越高,设计出来的数据表就越多、越精细,数据的冗余度就越低,进行数据查询的时候就可能需要关联多张表,这不但代价昂贵,也可能使一些索引策略无效
范式只是提出了设计的标准,实际上设计数据表时,未必一定要符合这些标准。开发中,我们会出现为了性能和读取效率违反范式化的原则,通过增加少量的冗余或重复的数据来提高数据库的读性能,减少关联查询,join表的次数,实现空间换取时间的目的。因此在实际的设计过程中要理论结合实际,灵活运用。

反范式化

规范化VS性能

  1. 为满足某种商业目标 , 数据库性能比规范化数据库更重要
  2. 在数据规范化的同时 , 要综合考虑数据库的性能
  3. 通过在给定的表中添加额外的字段,以大量减少需要从中搜索信息所需的时间
  4. 通过在给定的表中插入计算列,以方便查询

应用举例

举例1:
员工的信息存储在 employees 表 中,部门信息存储在 departments 表 中。通过 employees 表中的 department_id字段与 departments 表建立关联关系。如果要查询一个员工所在部门的名称:

select employee_id,department_name
from employees e join departments d
on e.department_id = d.department_id;

如果经常需要进行这个操作,连接查询就会浪费很多时间。可以在 employees 表中增加一个冗余字段 department_name,这样就不用每次都进行连接操作了。
举例2:
我们有 2 个表,分别是 商品流水表(atguigu.trans )和 商品信息表(atguigu.goodsinfo) 。商品流水表里有 400 万条流水记录,商品信息表里有 2000 条商品记录。
商品流水表:
image.png
商品信息表:
image.png
新的商品流水表
image.png

反范式化的新问题

  1. 存储空间变大了
  2. 一个表中字段做了修改,另一个表中冗余的字段也需要做同步修改,否则 数据不一致
  3. 若采用存储过程来支持数据的更新、删除等额外操作,如果更新频繁,会非常 消耗系统资源
  4. 在数据量小的情况下,反范式不能体现性能的优势,可能还会让数据库的设计更加复杂

反范式化的适用场景

当冗余信息有价值或者能 大幅度提高查询效率 的时候,我们才会采取反范式的优化。
历史快照/数据需要进行反范式化
在现实生活中,我们经常需要一些冗余信息,比如订单中的收货人信息,包括姓名、电话和地址等。每 次发生的 订单收货信息 都属于 历史快照 ,需要进行保存,但用户可以随时修改自己的信息,这时保存这 些冗余信息是非常有必要的。
反范式优化也常用在 数据仓库 的设计中,因为数据仓库通常 存储历史数据 ,对增删改的实时性要求不 强,对历史数据的分析需求强。这时适当允许数据的冗余度,更方便进行数据分析。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

指挥部在下面

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值