数据库表设计的三大范式

原创
2020/06/16 18:35
阅读数 74

数据库表设计有很多种范式,这里主要写三种常见范式,以备面试使用。

参考链接:William Kent, "A Simple Guide to Five Normal Forms in Relational Database Theory", Communications of the ACM 26(2), Feb. 1983, 120-125.

第一范式

第一种范式处理记录类型的“形状”,也就是规定表的二维结构:

  1. 每一行都有相同的列;
  2. 没有重复的列和行;

本质上这一定义也是关系型数据库的基本定义。

对比

和MongoDB等schemaless的数据库比较可以发现,MongoDB这类数据库的记录(Mongo称之为Document)是没有这种二维结构的,对js一类的脚本语言更友好,一个Document可以直接映射成一个对象,同一个collection的Document也不一定有相同的字段,甚至同一个collection里可能两个Document没有一个相同的字段。

这让mongodb这类数据库有足够的灵活性应对复杂的业务场景,开发简单,运维难度比传统RDBMS小得多。

而像是Redis这样的KV数据库则比传统RDBMS更加简化,没有表的概念,直接把数据结构暴露给用户。这让redis简单快速,但不适合应付复杂的业务场景。因此redis大多时候就是拿来当缓存和共享数据的。

第二范式

第二范式和第三范式处理键(key)字段和非键字段之间的关系,在第一范式基础上加入新的原则:任意一个非主属性都完全函数依赖于主键。

举例来说,在一个系统内部的通讯录表中。

姓名 固定电话 地址
张三 xxx-xxx-xxxx 派出所
张三 yyy-yyy-yyyy 看守所
李四 yyy-yyy-yyyy 看守所

假设一个地址只有一个固定电话可用,我们注意到电话是和地址相关的,但并不完全函数依赖于主键,也就是姓名。

这样会造成很多问题:

  1. 冗余。
  2. 更新地址或电话需要更新多条记录

等等。正确做法是拆成两个表,其中一个表以姓名和地址作为主键。

这段比较绕,我也头晕。建议读读参考链接里的文章。

第三范式

第三范式的主要是在第二范式基础上规定消除传递依赖性。

举个工资表的例子。

姓名 职务 职称 基本薪资 职务工资
张三 MT 高级干员 10000 2000
李四 TK 中级干员 8000 1500
王五 划水 初级干员 4000 0

首先我们了解到,基本薪资是由职称决定的。可以注意到,其中每个字段都和主键姓名成完全函数依赖,通过姓名可以唯一确定这人的基本薪资和职务工资,符合第二范式;

但如果注意看的话会注意到,主键姓名先唯一确定了职务和职称,再由职务和职称间推出实际工资数字的。这种依赖称为基本薪资传递函数依赖于主键姓名。

如果要符合第三范式,那么应该拆分为三张表:

  1. 职务工资表
  2. 职称工资表
  3. 员工表

其中员工表应该是这样

姓名 职务 职称
张三 MT 高级干员
李四 TK 中级干员
王五 划水 初级干员

职务工资表如下

职务 工资
MT 2000
TK 1500
划水 0

基本工资同理,不列举了。

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
0 评论
0 收藏
0
分享
返回顶部
顶部