数据库概念——范式与 schema 的优化设计

数据库概念——范式与 schema 的优化设计

对于给定的数据通常都有很多中表示方法,从完全的范式化到完全的反范式化,以及两者的这种。在范式化的数据库中,每个事实数据会出现并且只出现一次。相反,
在反范式化的数据库中,信息是冗余的,可能会存储在多个地方。

范式

范式的优点和缺点

当为性能问题而寻求帮助时,经常会被建议对 schema 进行范式化设计,尤其是写密集的场景。这通常是个好建议。因为这些原因,范式化通常能够带来好处:

  • 范式化的更新操作通常比反范式化要快。
  • 当数据较好地范式化时,就只有很少或者没有重复数据,所以只需要修改很少的数据。
  • 范式化的表通常更小,可以更好地放在内存里,所以执行操作会更快。
  • 很少有多余的数据意味着检索列表数据时更少需要 DISTINCT 或者 GROUP BY 语句。还是前面的例子:在非范式化的结构中必须使用 DISTINCT 或者 GROUP
    BY 才能获得一份唯一的部门列表,但是如果部门(DEPARTMENT)是一张单独的表,则只需要简单的查询这张表就行了。

范式化设计的 schema 的缺点是通常需要关联。稍微复杂一些的查询语句在符合范式的 schema 上都可能需要至少一次关联,也许更多。这不但代价昂贵,也可能使
一些索引策略无效。例如,范式化可能将列存放在不同的表中,而这些列如果在一个表中本可以属于同一个索引。

反范式的优点和缺点

反范式化的 schema 因为所有数据都在一张表中,可以很好的避免关联。

如果不需要关联表,则对大部分查询最差的情况——即使表没有使用索引——是全表扫描。当数据比内存大时这可能比关联要快得多,因为这样避免了随机 I/O。(
全表扫描基本上是顺序 I/O)

混用范式化和反范式化

范式化和反范式化的 schema 各有优劣,怎么选择最佳的设计?

事实是,完全的范式化和完全的反范式化 schema 都是实验室里才有的东西:在真是世界里很少会这么极端的使用。在实际应用中经常需要混用,可能使用部分范式
化的 schema、缓存表,以及其他技巧。

最常见的反范式化数据的方法是复制或者缓存,在不同的表中存储相同的特定列。在 MySQL 5.0 和更新版本中,可以使用触发器更新缓存值,这使得实现这样的方案
变得更简单。

缓存表和汇总表

有时提升性能最好的方法是在同一张表中保存衍生的冗余数据。然而,有时也需要创建一张完全独立的汇总表或缓存表。

术语 “缓存表” 和 “汇总表” 没有标准的含义。我们用术语 “缓存表” 来表示存储那些可以比较简单地从 schema 其他表获取(但是每次获取的速度比较慢)数据的表
(例如,逻辑上冗余的数据)。而术语 “汇总表”,则保存的是使用 GROUP BY 语句聚合数据的表。

计数器表

如果应用在表中保存计数器,则在更新计数器时可能碰到并发问题。计数器表在 web 应用中很常见。可以用这种表缓存一个用户的朋友数、文件下载次数等。创建
一张独立的表存储计数器通常是个好主意,这样可使计数器表小且快。使用独立的表可以帮助避免查询缓存失效,。

更快的读,更慢地写

为了提升查询的速度,经常会需要建一些额外索引,增加冗余列,甚至是创建缓存表和汇总表。这些方法会增加写查询的负担,也需要额外的维护任务,但在设计高性能
数据库时,这些都是常见的技巧:虽然写操作变得更慢了,但更显著地提高了读操作的性能。

然而,写操作变慢并不是读操作变得更快所付出的唯一代价,这可能同时增加了读操作和写操作的开发难度。

参考

  • 高性能 MySQL 第3版 Baron

你可能感兴趣的:(数据库)