关于数据库设计

关于数据库设计的规范

鄙人对于数据库设计理解的加深得益于我老师的引导,直接发链接,胖先生的博客地址: http://pangsir8983.github.io/ ,虽然对于数据库的理解深刻了许多,但是在层次上仍处于小白阶段。如果说让自己组织语言来表达的话还是会有所欠缺,下面就通过多方面信息搜集结合自己的理解来说明一下数据库建表的一些简单要求,那就先从范式入手吧!

范式是什么?

你可以把它粗略地理解为一张数据表的表结构所符合的某种设计标准的级别。

  • 目前关系数据库有六种范式:
    • 第一范式(1NF)
    • 第二范式(2NF)
    • 第三范式(3NF)
    • 巴斯-科德范式(BCNF)
    • 第四范式(4NF)
    • 第五范式(5NF,还又称完美范式)

对于普通数据库设计来说,我们最多考虑到第三范式(1NF、2NF、3NF)就可以了。
下面我们就分别说说这三个范式的含义吧!

1NF

第一范式:1NF是对属性的原子性约束,要求属性具有原子性,不可再分解;

如下图:

第一范式错误示例

(字段我这里用的是中文,直观一点)可以看出not_1NF属性可以在分为系、届、班级等等。所以not_1NF属性就不符合1NF的要求。1NF是所有 关系型数据库 的最基本要求。
现在对数据表进行修改,使其满足1NF。如下图:

满足1NF示例

但是仅仅符合1NF的设计,仍然会存在数据冗余过大,插入异常,删除异常,修改异常的问题。

  • 每一名学生的账号、密码、系名、年级、班级等数据重复多次。每个系与对应的系主任的数据也重复多次—— 数据冗余过大
  • 假如学校新建了一个系,但是暂时还没有招收任何学生(比如3月份就新建了,但要等到8月份才招生),那么是无法将系名与系主任的数据单独地添加到数据表中去的—— 插入异常
  • 假如将某个系中所有学生相关的记录都删除,那么所有系与年级班级的数据也就随之消失了(一个系所有学生都没有了,并不表示这个系就没有了)。——删除异常
  • 假如张三转系到网络工程系,那么为了保证数据库中数据的一致性,需要修改三条记录中系与系主任的数据。—— 修改异常

码:关系中的某个属性或者某几个属性的组合,用于区分每个元组(可以把“元组”理解为一张表中的每条记录,也就是每一行)。
如:主键是确保每条记录唯一的属性,就可以称为码!假如下图中,学号字段不唯一(每个系都存在相同的学号),需要‘学号+系’来确保每条记录的唯一,那么就可以称‘学号+系’ 为这张表的码!如下图:

由多个属性组成的码

正因为仅符合1NF的数据库设计存在着这样那样的问题,我们需要提高设计标准,去掉导致上述四种问题的因素,使其符合更高一级的范式(2NF),
这就是所谓的“规范化”。

2NF

第二范式:消除非主属性对主属性(码)的部分函数依赖

第二范式的出现就是为了解决上述的问题!

首先先介绍一下函数依赖、完全函数依赖、部分函数依赖、传递函数依赖的区别:

  • 函数依赖:若在一张表中,在属性(或属性组)X的值确定的情况下,必定能确定属性Y的值,那么就可以说Y函数依赖于X,写作 X → Y。
  • 完全函数依赖:若 X → Y,且对于 X 的任何一个真子集(假如属性组 X 包含超过一个属性的话),X ‘ → Y 不成立,那么我们称 Y 对于 X 完全函数依赖。例如:主属性[学号] → 姓名、或 主属性[学号+课程] → 唯一成绩。都属于后者完全依赖前者。
  • 部分函数依赖:假如 Y 函数依赖于 X,但同时 Y 并不完全函数依赖于 X。例如:主属性[学号+课程] → 姓名。前者可以确定后者,但后者并不是完全由前者决定,并不依赖于课程,依赖于学号。所以是部分函数依赖。
  • 传递函数依赖:假如 Z 函数依赖于 Y,且 Y 函数依赖于 X (严格来说还有一个X 不包含于Y,且 Y 不函数依赖于Z的前提条件),那么我们就称 Z 传递函数依赖于 X
    例如:主属性[学号] → 该学生的系名 → 由系名可知系主任。对于这样的关系,我们就称之为传递函数依赖。

回到第二范式!!

根据部分依赖定义,第二范式的规则是要求数据表里的所有数据都要和该数据表的主键不存在部分依赖关系;如果有哪些数据和主键存在部分依赖关系,它就不符合第二范式。

按照定义试图去满足第二范式(主属性学号唯一),已知学号可确定系别,已知系别无法确定学号。是部分函数依赖关系。依次除去系别、年级、班级、课程部分函数依赖关系(分数不符合部分函数依赖关系,由前者无法确定后者,同样已知后者无法确定前者)。除去部分函数依赖关系后如下图:

满足2NF示例

当我们消掉部分函数依赖关系之后。发现,分数依旧还在。这时候,我们就需要用到第三范式去解决这个问题了。

3NF

第三范式:消除非主属性对于主属性的传递函数依赖

先po图:

满足2NF示例

图中的课程依赖于学号,分数依赖于课程,可知:学号与分数之间存在传递函数依赖关系。当在第二范式中消除了部分函数依赖关系之后,对于所剩下的分数字段就要通过第三范式,消除传递函数依赖。
解决办法就是将一张包含多个可以作为主属性的数据表拆分成多个数据表,通过外键关联。如果是多对多的关系可以在两张表添加外键建立一张中间表来表示多对多的关系。当满足了第三范式之后,那么我们就可以得到一个由多张设计合理的数据表组成的数据库了。

总结一下:

- 第一范式是对属性原子性的要求。
- 第二范式和第三范式个人感觉是一起用的。第二范式消除部分函数依赖,第三范式消除传递函数依赖,合起来总的说就是使得所有非主属
  性完全依赖于主属性。这是第二范式和第三范式的目的。
- 至于关于关联表的关系。关联表其实存储的信息只有两张表的主键和自己的主键。关联表的码就是两张表的主键,确保属性的唯一性,使
  得两张表对应的关系唯一,例如:一个学生对应一个班级只需要在中间表存学生ID和班级ID建立对应关系。

完整关系如下图:

满足3NF示例图片

对于普通的数据库设计,满足前面三个范式就已经足够了!本来参考知乎文章(题主有po BCNF,有兴趣戳原文),结合自己的理解。如有不够准确的地方,欢迎指正!
参考知乎 https://www.zhihu.com/question/24696366