数据库范式学习笔记
了解数据库范式,作为关系数据库表设计的理论基础之一,主要学习了知乎上的文章——数据库第一二三范式到底在说什么?,这篇只是重新整理归纳,同时作为个人梳理思路,大部分内容和示例来自该文章
范式
什么是范式
数据库的范式(normal forms),在讨论时通常被缩写成NF,指的是关系数据库内部数据联系的合理化程度,文中1总结为一张表的表结构所符合的某种设计标准的级别,级别从低到高分1NF,2NF,3NF,BCNF,4NF,5NF。在日常关系数据库设计中,通常最多考虑到BCNF就足够,至于为什么,在了解完范式之后,会在文章后面进一步讨论反范式
第一范式(1NF)
先看定义和结论:符合1NF的关系中的每个属性都不可再分,也就是说,如果一张表是符合1NF的,那么其每个字段都是独立的,没有包含其它字段的,所有关系型数据库系统(RDBMS)的表设计,都是符合1NF的,看图可以理解:
不符合1NF的表设计:
编号 | 品名 | 进货 | 销售 | 备注 | ||
---|---|---|---|---|---|---|
数量 | 单价 | 数量 | 单价 | |||
符合1NF的表设计:
编号 | 品名 | 进货数量 | 进货单价 | 销售数量 | 销售单价 | 备注 |
---|---|---|---|---|---|---|
第二范式(2NF)
直接来看这个表:
学号 | 姓名 | 系名 | 系主任 | 课名 | 分数 |
---|---|---|---|---|---|
95001 | 李勇 | 数学系 | 张清玫 | 复变函数 | 80 |
95001 | 李勇 | 数学系 | 张清玫 | 大学英语 | 90 |
95001 | 李勇 | 数学系 | 张清玫 | 数学分析 | 70 |
95002 | 刘晨 | 计算机系 | 刘逸 | 数据结构 | 65 |
95002 | 刘晨 | 计算机系 | 刘逸 | Java程序设计 | 90 |
95002 | 刘晨 | 计算机系 | 刘逸 | 数据库原理 | 65 |
95003 | 王敏 | 数学系 | 张清玫 | 复变函数 | 80 |
95003 | 王敏 | 数学系 | 张清玫 | 红楼梦赏析 | 85 |
2NF在1NF的基础上,消除了非主属性对于码的部分函数依赖
函数依赖:若在一张表中,在属性(或属性组)X的值确定的情况下,必然能确定属性Y的值,就可以说Y函数依赖与X
函数依赖又分三种:
完全函数依赖:在一个属性的值确定的情况下,必然能确定属性Y的值
部分函数依赖:若属性Y不完全依赖于一个属性组(大于一个属性)X,则Y部分函数依赖于X
传递函数依赖:假如Z函数依赖于Y,且Y函数依赖于X,则Z传递依赖于X
主属性,非主属性,码
码是一个概念,若X为表中的一个属性或属性组,若除X之外所有的属性都完全函数依赖与X,则X就是这个表的码,一个表可以有多个码
主属性/非主属性:包含在任意一个码中的属性称为主属性,不包含在任何一个码中的属性称为非主属性
现在让我们来分析上方表的内部关系
因为其它属性都完全函数依赖于学号或课名,只需要这两个属性确定了,则可以确定表中的所有其它内容,所以这个表的码是(学号,课名)
非主属性是:姓名,系名,系主任,分数
为了消除非主属性对于码的部分函数依赖,使其满足2NF范式,这种让表满足更高范式的行为,称为模式分解
分解过程:
可以看到,除了分数之外(分数需要学号和课名一起确定),因为姓名,系名,系主任是部分函数依赖于码的,我们需要消除这一部分函数依赖,所以把表拆为
学生信息表:
学号 | 姓名 | 系名 | 系主任 |
---|---|---|---|
分数表:
学号 | 课名 | 分数 |
---|---|---|
可以看到通过模式分解把码中的属性拆分到不同的表,消除了非主属性对码的部分依赖,使其满足了2NF范式
第三范式(3NF)
3NF:消除非主属性对码的传递依赖
观察发现因为系主任完全函数依赖于系名,系名完全函数依赖于学号,所以这里存在传递依赖关系,将其进一步进行模式分解
分解后的表为:
学生表:
学号 | 姓名 | 系名 |
---|---|---|
成绩表:
学号 | 课名 | 分数 |
---|---|---|
系别表:
系名 | 系主任 |
---|---|
BC范式(BCNF)
BCNF:消除主属性对于码的部分与传递函数依赖
换句话说就是在2NF和3NF时对非主属性做的操作,现在要对主属性也检查并操作一次
直接看例子:
仓库名 | 管理员 | 物品名 | 数量 |
---|---|---|---|
主属性为仓库名,管理员,物品名
因为存在仓库名对于(管理员,物品名)的部分函数依赖,所以其不满足BCNF范式,拆分为
仓库信息表:
仓库名 | 管理员 |
---|---|
库存表
仓库名 | 物品名 | 数量 |
---|---|---|
反范式与范式2
反范式
顾名思义,就是不完全遵循数据库范式的数据库表设计,在反范式化的数据库中,信息是抗御的,可能会存在多个地方
高范式的优缺点
从性能角度上来说,尤其是写密集的场景,一个满足更高范式的数据库常常有以下优势:
- 范式化的更新操作通常比反范式要快
- 当数据较好地范式化时,就只有很少或者没有重复数据,所以只需要修改更少的数据。
- 范式化的表通常更小,可以更好地放在内存里,所以执行操作会更快
- 很少有多余的数据意味着检索数据时需要
DISTINCT
或者GROUP BY
语句
范式化设计的表的缺点是通常需要关联,稍微复杂一些的查询语句在符合范式的数据表上需要至少一次或更多关联,这不但代价昂贵,也可能使一些索引策略无效。例如,范式化可能将列存放在不同的表中,而这些列如果在一个表中本可以属于同一个索引
反范式的优缺点
优点:避免了关联,在大部分大量查询的情况中,比关联要快,因为避免了随机I/O,单独的表也能使用更有效的索引策略
混用范式化和反范式化
完全的范式化和完全的反范式化设计都是实验室里才有的东西,在真实情况中很少会这么极端的使用,一些有必要的冗(rong,三声)余经常被用来辅助索引或者统计等