数据库规范化,又称数据库或资料库的正规化、标准化,是数据库设计中的一系列原理和技术,以减少数据库中数据冗余,增进数据的一致性。关系模型的发明者埃德加·科德最早提出这一概念,并于1970年代初定义了第一范式、第二范式和第三范式的概念,还与Raymond F. Boyce于1974年共同定义了第三范式的改进范式——BC范式。
除外还包括针对多值依赖的第四范式,连接依赖的第五范式,DK范式和第六范式。
现在数据库设计最多满足3NF,普遍认为范式过高,虽然具有对数据关系更好的约束性,但也导致数据关系表增加而令数据库IO更易繁忙,原来交由数据库处理的关系约束现更多在数据库使用程序中完成。
范式
对于任何给定的数据库都有很多种表示方法,从完全的范式话到完全的反范式花,以及两者折中。在范式化的数据库中,每个事实数据只会出现一次,相反,在反范式花中,信息是冗余的。范式化就是消除数据的冗余,消除数据依赖。
一个常见的例子,“雇员、部门、部门精灵”的例子:
Employee | department | leader |
---|---|---|
Jones | Accounting | Jones |
Smith | Engineering | Smith |
Brown | Accounting | Jones |
Green | Engineering | Smith |
对这样一个schema ,显然其中有些数据是重复的,修改数据时可能发生不一致。加入 Brown 接任了 Accounting 部门的领导,那么需要修改很多行来反映这个变化,这很麻烦而且很容易出错,并且如果Smith这一行的 leader 和 Green 这一行的 leader 不一样,那就不知道到底谁是对的了,这就像 “一个人有两块手表就永远不知道正确时间了”。这样设计的一张表还存在很多问题,比如部门不存在雇员就没法表示一个部门,针对这些问题我们要对这张表进行范式化。
将表拆分是范式化的手段,将信息冗余的列从原表中拆分出来做一个新表,然后通过关联表建立联系。
Employee | department |
---|---|
Jones | Accounting |
Smith | Engineering |
Brown | Accounting |
Green | Engineering |
department | leader |
---|---|
Accounting | Jones |
Engineering | Smith |
拆分成两张表之后上面的问题就都解决了(第二范式),我们来看下范式存在的优缺点。
范式的优缺点
在解决数据库性能问题时,经常会被建议对 schema 进行范式化建议,尤其是写密集的场景。这通常是个好建议,范式话能带来这些好处:
- 范式化的数据更新操作通常比反范式化要快
- 当数据较好地范式化时,就只有很少或者没有重复数据,所以只需要修改更少的数据
- 范式化的表通常更小,可以更好地放在内存里,所以执行操作会很快
- 很少有多余的数据意味着检索列表数据时更少需要distinct 或者 group by 语句,在前面的例子中,需要使用 distinct 或者 group by 才能获得一份唯一的部门列表,如果部门是一种单独的表则只需要简单查询这张表就可以了
当然范式化的设计并不是只带来好处,范式化的schema带来的缺点是需要关联,稍微复杂一些的查询语句在符合范式的schema上都可能需要至少一次关联,甚至多次关联。关联的代价是很昂贵的,也可能使一些索引策略无效。例如范式化可能将列存在不同的表中,而这些列如果在同一表中本可以属于同一个索引。
反范式的优缺点
反范式就是在通过增加冗余数据或数据分组来提高数据库读性能的过程。有时候反范式能掩盖关系型数据库软件的低效。反范式的schema因为数据都在一张表中,可以很好的避免关联。
如果不需要关联表,则对大部分查询最差的情况–即使表没有使用索引–是全表扫描,当数据比内存还大的时候可能比关联表要快得多,因为这样避免了随机IO(扫描全表基本上是顺序IO)。使用反范式的表能使用更加有效的索引策略。
混合使用范式化和反范式化
完全的范式化和完全的反范式化 schema 都是实验室才有的东西:在真实世界不会有这么极端的使用,在实际应用中经常需要混用,可能使用部分范式化的schema、缓存表,以及其他技巧。
最常见的反范式化数据的方法是复制或者缓存,在不同的表中,存储相同的特定列。但是反范式化使得更新数据的代价变大了,需要考虑更新的频率以及更新的时常,并和执行select查询的频率进行比较。所以实际使用中,是否使用反范式化还是要根据具体需求确定,如果查询多余更新,可以反范式化多一些,如果需要经常更新数据,那么过多的反范式化列使得整体的性能反而降低了。
一般来说,在范式化达到一定的满意水平并且所需要的约束和规则都已经建立起来才进行反范式化。
从性能来说,范式化有更好的写性能,反范式化有更好的读性能。
参考: