【问题标题】:In what way does denormalization improve database performance?非规范化以何种方式提高数据库性能?
【发布时间】:2011-01-21 21:34:45
【问题描述】:

我听说过很多关于为提高某些应用程序的性能而进行的非规范化。但我从未尝试做任何相关的事情。

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

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

【问题讨论】:

  • 如果您还没有尝试过非规范化,那么我假设您也没有尝试过规范化?如果是这样,下面的答案可以帮助提供基于此的上下文...
  • 我开发的所有数据库(最大的有22个表)都是3NF。但是,如果您指的是编写所有属性并通过进一步规范化创建 1NF 的经典过程,那么您是对的,我从未觉得有必要这样做。
  • 非规范化有两个原因和不同的方式: 1. 历史 - 真实数据。 2. 速度(更少的连接) - 计算字段/索引。下面的答案模糊了这两种不同的方法。

标签: database performance database-design normalization denormalization


【解决方案1】:

反规范化通常用于:

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

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


一个简单的例子?

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

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

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

【讨论】:

  • 很好的例子,大多数人只想“加入”几个表。
  • +1 这是我遇到的反规范化最好的例子之一,非常感谢你,希望我能为它做+10
  • 这是一个非常好的例子,说明了使用非规范化的可接受案例,并且对性能有意义。我通常非常反对非规范化数据,但有时应该为了性能而这样做。
  • 我认为这是一个好主意,直​​到两个用户同时发布 cmets 并且结果是对该帖子的 +1 评论,因为两个线程都读取旧值并且使用的更新方法是天真的而不是将增量传递给查询。非规范化也会降低可维护性,不应将其视为成本。过早的优化......你知道它是怎么回事。索引上的连接工作得很好,当它成为一个问题时,我们才去规范化。
  • 那是个好人。但这是否意味着如果我正在构建一个应用程序,该应用程序具有帖子的评论部分或产品的评论部分,我可以为此目的使用 NoSQL 数据库?
【解决方案2】:

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

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

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

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

【讨论】:

  • 也是更新异常问题。正确规范化的数据库可以更新而不会发生奇怪的事情。非规范化数据库具有重复数据;一个副本的更新会出现异常。
  • 是的。 OP 仅在性能方面要求它。我没有从关系模型的角度来介绍它。
  • 顺便说一句,我应该说时空权衡,而不是性能空间。
  • 如果不提供一种方法来自动更新被非规范化的数据中的更改,则永远不应该进行非规范化。因此,如果您将用户名存储在两个位置,则需要一个触发器来确保它们保持同步。这将避免 S. Lott 所说的问题,这是大多数人忘记做的步骤。
  • DAvid,这并不是真正的非规范化,而是预期的设计。如果客户名称更改或地址更改或订购的零件价格更改,则订单不应更改。 Orders 表记录了一个时刻。
【解决方案3】:

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

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

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

与星型模式密切相关的是雪花模式,它有点复杂。

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

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

【讨论】:

    【解决方案4】:

    反规范化的关键问题是:

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

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

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

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

    【讨论】:

      【解决方案5】:

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

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

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

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

      【讨论】:

      • 如果您设计得当以保持更新,预先计算的值不会过时。或者,如果您选择仅定期更新,用户需要知道这些值是一天前的(或无论更新时间范围如何)。
      • @HLGEM:这就是我的意思 - 您需要根据需要自动更新它们(当基础数据更改时),或者您的用户需要注意它们可能稍微不同步(例如直到他们在一夜之间重新计算,或类似的东西)。
      【解决方案6】:

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

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

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

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

      考虑将其反规范化为一个只有子行的单个表,2x p。读取的行数是 2x p。

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

      【讨论】:

      • 我不相信这是完全正确的......因为列存储索引......但只是我的意见
      【解决方案7】:

      根据本文最后一节,

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

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

      【讨论】:

        【解决方案8】:

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

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-01-07
          • 2011-02-15
          • 2021-09-22
          • 2014-08-29
          • 2012-03-12
          • 2014-06-06
          • 2012-10-08
          • 1970-01-01
          相关资源
          最近更新 更多