67

我听到了很多关于非规范化的信息,这些非规范化是为了提高某些应用程序的性能。但我从未尝试做任何相关的事情。

所以,我只是好奇,规范化数据库中的哪些地方会使性能变差,或者换句话说,什么是非规范化原则?

如果我需要提高性能,我该如何使用这种技术?

4

8 回答 8

92

非规范化通常用于:

  • 避免一定数量的查询
  • 删除一些连接

非规范化的基本思想是您将添加冗余数据或将一些数据分组,以便能够更轻松地获取这些数据 - 成本更低;这对表演更好。


一个简单的例子?

  • 考虑一个博客的“帖子”和“评论”表
    • 对于每个帖子,您将在“评论”表中有几行
    • 这意味着要显示具有相关评论数量的帖子列表,您必须:
      • 执行一项查询以列出帖子
      • 每个帖子进行一次查询以计算它有多少评论(是的,这些可以合并为一个,以一次获取所有帖子的数量)
      • 这意味着几个查询。
  • 现在,如果您在 Posts 表中添加“评论数”字段:
    • 您只需要一个查询即可列出帖子
    • 并且无需查询 Comments 表:评论的数量已经非规范化到 Posts 表。
    • 并且只有一个返回多一个字段的查询优于更多查询。

现在,有一些成本,是的:

  • 首先,这会在磁盘和内存中占用一些空间,因为您有一些冗余信息:
    • 评论数存储在 Posts 表中
    • 您还可以在评论表中找到这些数字
  • 其次,每次有人添加/删除评论时,您必须:
    • 当然,保存/删除评论
    • 而且,更新 Posts 表中的相应数字。
    • 但是,如果你的博客阅读的人比写评论的人多得多,这可能还不错。
于 2010-02-27T23:00:22.133 回答
76

非规范化是一种时空权衡。规范化数据占用的空间更少,但可能需要连接来构建所需的结果集,因此需要更多时间。如果它是非规范化的,则数据会在多个地方复制。然后它会占用更多空间,但所需的数据视图很容易获得。

还有其他的时空优化,比如

  • 非规范化视图
  • 预先计算的列

与任何此类方法一样,这改进了读取数据(因为它们很容易获得),但更新数据变得更加昂贵(因为您需要更新复制或预先计算的数据)。

于 2010-02-27T23:01:44.653 回答
12

“非规范化”一词会导致设计问题的混淆。试图通过非规范化获得高性能数据库就像试图从纽约开车去目的地一样。它不会告诉你走哪条路。

你需要的是一个好的设计学科,一个能够产生简单而合理的设计的学科,即使该设计有时与规范化规则相冲突。

一种这样的设计原则是星型模式。在星型模式中,单个事实表充当星型表的中心。其他表称为维度表,它们位于模式的边缘。维度通过看起来像轮辐的关系连接到事实表。星型模式基本上是将多维设计投射到 SQL 实现上的一种方式。

与星型模式密切相关的是雪花模式,它稍微复杂一些。

如果你有一个好的星型模式,你将能够获得各种各样的数据组合,不超过三路连接,涉及两个维度和一个事实表。不仅如此,许多 OLAP 工具将能够自动破译您的星形设计,让您无需进一步编程即可对数据进行点击、向下钻取和图形分析访问。

星型模式设计偶尔会违反第二和第三范式,但它会提高报告和提取的速度和灵活性。它最常用于数据仓库、数据集市和报告数据库。星型模式或其他一些面向检索的设计通常会比随意的“非规范化”获得更好的结果。

于 2010-02-28T14:38:31.523 回答
7

非规范化的关键问题是:

  • 决定要复制哪些数据以及为什么
  • 规划如何保持数据同步
  • 重构查询以使用非规范化字段。

最简单的非规范化类型之一是将标识字段填充到表中以避免连接。由于身份永远不会改变,这意味着保持数据同步的问题很少出现。例如,我们将客户端 ID 填充到多个表中,因为我们经常需要通过客户端查询它们,并且在查询中不一定需要在客户端表和我们正在查询的表之间的表中的任何数据如果数据完全标准化。您仍然需要进行一次连接才能获取客户端名称,但这比连接到 6 个父表来获取客户端名称要好,因为这是您需要从正在查询的表之外获取的唯一数据。

但是,除非我们经常在需要来自中间表的数据的情况下进行查询,否则这样做没有任何好处。

另一种常见的非规范化可能是将名称字段添加到其他表。由于名称本质上是可变的,因此您需要确保名称与触发器保持同步。但是,如果这使您免于加入 5 个表而不是 2 个表,那么花费稍长的插入或更新成本是值得的。

于 2010-03-02T14:29:06.033 回答
3

如果您有某些要求,例如报告等,它可以帮助您以各种方式对数据库进行非规范化:

  • 引入某些数据重复以节省一些JOIN(例如将某些信息填充到表中并可以处理重复数据,以便该表中的所有数据都不需要通过加入另一个表来找到)

  • 您可以预先计算某些值并将它们存储在表列中,以便在每次查询数据库时即时计算它们。当然,随着时间的推移,这些计算值可能会变得“陈旧”,您可能需要在某个时候重新计算它们,但是仅仅读取一个固定值通常比计算一些东西便宜(例如计算子行)

当然还有更多方法可以对数据库模式进行非规范化以提高性能,但您只需要注意这样做确实会给自己带来一定程度的麻烦。在做出这些决定时,您需要仔细权衡利弊 - 性能优势与您遇到的问题。

于 2010-02-27T23:03:33.273 回答
1

考虑一个具有适当规范化父子关系的数据库。

假设基数是 2x1 的平均值。

你有两个表,父级,有p行。具有 2x p行的子级。

连接操作意味着对于p个父行,必须读取2x p个子行。读取的总行数为p + 2x p

考虑将其反规范化为仅包含子行 2x p的单个表。读取的行数是 2x p

更少的行 == 更少的物理 I/O == 更快。

于 2010-02-27T23:02:50.730 回答
0

根据本文最后一节,

https://technet.microsoft.com/en-us/library/aa224786%28v=sql.80%29.aspx

可以使用虚拟非规范化,您可以使用一些非规范化数据创建视图以更快地运行更简单的 SQL 查询,而底层表保持规范化以加快添加/更新操作(只要您可以定期更新视图而不是比实时)。我自己只是在上一门关于关系数据库的课程,但是从我一直在阅读的内容来看,这种方法对我来说似乎是合乎逻辑的。

于 2015-02-20T00:32:44.173 回答
-7

去规范化相对于规范化的好处

基本上,反规范化用于 DBMS 而不是 RDBMS。正如我们所知,RDBMS 与规范化一起工作,这意味着没有一次又一次的重复数据。但是在使用外键时仍然会重复一些数据。

当您使用 DBMS 时,需要删除规范化。为此,需要重复。但是,它仍然提高了性能,因为表之间没有关系,并且每个表都具有不可分割的存在。

于 2012-11-08T12:13:52.547 回答