非规范化以何种方式提高数据库性能?

时间:2010-02-27 22:55:33

标签: database performance database-design normalization denormalization

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

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

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

8 个答案:

答案 0 :(得分:84)

非规范化通常用于:

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

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


一个简单的例子?

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

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

  • 首先,这会占用磁盘和内存中的某些位置,因为您有一些冗余信息:
    • 评论数量存储在帖子表格
    • 您还可以在评论表中找到这些数字
  • 其次,每当有人添加/删除评论时,您必须:
    • 保存/删除评论,当然
    • 但是,请更新帖子表中的相应号码。
    • 但是,如果您的博客阅读的人数多于撰写评论,那么这可能并不是那么糟糕。

答案 1 :(得分:69)

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

还有其他时空优化,例如

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

与任何此类方法一样,这可以改善阅读数据(因为它们随时可用),但更新数据变得更加昂贵(因为您需要更新已复制的数据)或预先计算的数据)。

答案 2 :(得分:11)

“非规范化”一词导致设计问题混乱。试图通过非规范化获得高性能数据库就像试图通过远离纽约来到达目的地。它没有告诉你走哪条路。

您需要的是一个好的设计学科,即使该设计有时会与规范化规则相冲突,也能产生简单而完善的设计。

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

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

如果你有一个好的星型模式,你将能够获得各种各样的数据组合,只需要一个三向连接,包括两个维度和一个事实表。不仅如此,许多OLAP工具还能够自动解读您的星形设计,并为您提供点击,向下钻取和图形分析访问您的数据,无需进一步编程。

星型模式设计偶尔会违反第二和第三种常规形式,但它会为报告和摘录带来更快的速度和灵活性。它最常用于数据仓库,数据集市和报告数据库。你通常可以从星型模式或其他一些面向检索的设计中得到更好的结果,而不仅仅是偶然的“非规范化”。

答案 3 :(得分:7)

非规范化的关键问题是:

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

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

但是,除非我们经常查询需要来自干预表的数据,否则没有任何好处。

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

答案 4 :(得分:3)

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

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

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

    < / LI>

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

答案 5 :(得分:1)

考虑具有正确规范化的父子关系的数据库。

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

您有两个表,Parent, p 行。 2x p 行的孩子。

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

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

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

答案 6 :(得分:0)

根据本文的最后一部分,

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

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

答案 7 :(得分:-6)

去标准化优于标准化的好处

基本上,去标准化用于DBMS而不是用于RDBMS。我们知道RDBMS可以正常化,这意味着不会一次又一次地重复数据。但是在使用外键时仍然会重复一些数据。

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