何时以及为什么数据库加入昂贵?

时间:2008-10-06 09:52:19

标签: database performance join relational-database denormalization

我正在研究数据库,我正在研究关系数据库的一些局限性。

我得到大表的连接非常昂贵,但我不完全确定为什么。 DBMS需要做什么来执行连接操作,瓶颈在哪里?
非规范化如何帮助克服这笔费用?其他优化技术(例如索引)如何帮助?

欢迎个人经历!如果您要发布资源链接,请避免使用Wikipedia。我知道在哪里找到它。

与此相关,我想知道云服务数据库(如BigTable和SimpleDB)使用的非规范化方法。请参阅this question

7 个答案:

答案 0 :(得分:448)

答案 1 :(得分:43)

大多数评论者没有注意到的是复杂的RDBMS中可用的各种连接方法,并且非规范化器总是掩盖维护非规范化数据的更高成本。并非每个连接都基于索引,并且数据库有许多优化的算法和连接方法,旨在降低连接成本。

在任何情况下,连接的成本取决于其类型和一些其他因素。它根本不需要昂贵 - 一些例子。

  • 散列连接,其中批量数据是等距的,确实非常便宜,并且如果散列表不能缓存在内存中,则成本才会变得显着。无需索引。联接数据集之间的等分区可以提供很大的帮助。
  • 排序合并连接的成本是由排序成本而不是合并驱动的 - 基于索引的访问方法实际上可以消除排序成本。
  • 索引上嵌套循环连接的开销由b-tree索引的高度和表块本身的访问权限驱动。它很快,但不适合批量连接。
  • 基于群集的嵌套循环连接要便宜得多,每个连接行需要的逻辑IO IO更少 - 如果连接的表都在同一个群集中,那么通过连接行的共置,连接变得非常便宜。

数据库旨在加入,并且他们在执行操作方面非常灵活,并且除非他们使连接机制出错,否则通常非常高效。

答案 2 :(得分:27)

我认为整个问题是基于错误的前提。大型表上的连接必然是昂贵的。实际上,有效地进行连接是关系数据库存在的主要原因之一。加入大型通常很昂贵,但是很少想要将大表A的全部内容与大表B的全部内容一起加入。相反,您要编写查询以便仅使用每个表的重要行,并且连接保留的实际集保持较小。

此外,您还具有Peter Wone提到的效率,因此在实现最终结果集之前,只有每条记录的重要部分需要在内存中。此外,在具有许多联接的大型查询中,您通常希望从较小的表集开始,然后一直运行到大表集,以便保留在内存中的集尽可能地尽可能小。

如果操作正确,联接通常是最佳方式来比较,组合或过滤大量数据。

答案 3 :(得分:11)

瓶颈几乎总是磁盘I / O,更具体地说 - 随机磁盘I / O(相比之下,顺序读取相当快,可以通过预读策略进行缓存)。

加入可以增加随机搜索 - 如果你正在跳读大表的一小部分。但是,查询优化器会查找它并将其转换为顺序表扫描(丢弃不需要的行),如果它认为更好。

单个非规范化表具有类似的问题 - 行很大,因此不太适合单个数据页。如果您需要远离另一行的行(并且大行大小使它们更远),那么您将拥有更多随机I / O.同样,可以强制进行表扫描以避免这种情况。但是,这一次,由于行的大小,您的表扫描必须读取更多数据。除此之外,您将将数据从一个位置复制到多个位置,而RDBMS还有更多内容可供阅读(和缓存)。

使用2个表,您还可以获得2个聚簇索引 - 并且通常可以索引更多(因为插入/更新开销较少),这可以大大提高性能(主要是,因为索引(相对)小,快速到读取磁盘(或廉价缓存),并减少需要从磁盘读取的表行数。)

关于连接的唯一开销来自于找出匹配的行。 Sql Server使用3种不同类型的连接(主要基于数据集大小)来查找匹配的行。如果优化器选择了错误的连接类型(由于统计信息不准确,索引不足,或只是优化器错误或边缘情况),它可能会极大地影响查询时间。

  • 对于(至少1个)小数据集,循环连接非常便宜。
  • 合并连接首先需要两种数据集。但是,如果您加入索引列,则索引已经排序,无需进一步的工作。否则,排序会产生一些CPU和内存开销。
  • 散列连接需要内存(用于存储散列表)和CPU(用于构建散列)。同样,这对于磁盘I / O来说相当快。 然而,如果没有足够的RAM来存储哈希表,Sql Server将使用tempdb来存储哈希表的部分内容和找到的行,然后一次只处理哈希表的一部分。与所有磁盘一样,这是相当慢的。

在最佳情况下,这些不会导致磁盘I / O - 因此从性能角度来看可以忽略不计。

总而言之,最糟糕的是 - 从x连接表中读取相同数量的逻辑数据实际上应该更快,因为它来自单个非规范化表,因为磁盘读取较小。要读取相同数量的物理数据,可能会有一些轻微的开销。

由于查询时间通常由I / O成本决定,并且数据的大小不会随着非规范化而改变(减去一些非常微小的行开销),因此将表合并在一起并不会带来巨大的好处。倾向于提高性能的非规范化类型IME是缓存计算值而不是读取计算它们所需的10,000行。

答案 4 :(得分:4)

您加入表格的顺序非常重要。如果您有两组数据,请尝试以某种方式构建查询,以便首先使用最小的数据来减少查询必须处理的数据量。

对于某些数据库而言无关紧要,例如MS SQL在大多数情况下确实知道正确的连接顺序。 对于某些人(如IBM Informix),订单会产生重大影响。

答案 5 :(得分:0)

当您考虑连接的复杂性类时,确定是否进行非规范化或规范化是一个相当简单的过程。例如,当查询为O(k log n)时,我倾向于使用规范化来设计我的数据库,其中k是相对于所需输出幅度的。

对异常化和优化性能的简单方法是考虑规范化结构的更改如何影响非规范化结构。然而,它可能会有问题,因为它可能需要事务逻辑来处理非规范化的结构化。

关于正常化和非规范化的争论不会结束,因为问题是巨大的。自然解决方案需要两种方法存在许多问题。

作为一般规则,我总是存储一个可以重构的规范化结构和非规范化缓存。最终,这些缓存可以解决我未来的规范化问题。

答案 6 :(得分:-7)

阐述别人所说的话,

加入只是具有一些唇彩的笛卡儿产品。 {1,2,3,4} X {1,2,3}会给我们12个组合(nXn = n ^ 2)。此计算集充当应用条件的参考。 DBMS应用条件(如左右两个都是2或3)给出匹配条件。实际上它更优化但问题是相同的。对集合大小的更改会以指数方式增加结果大小。消耗的内存量和CPU周期均以指数形式实现。

当我们非规范化时,我们完全避免这种计算,想想有一个彩色粘性,附在你书的每一页上。您可以使用引用推断出信息。我们付出的代价是我们正在妥协DBMS(数据的最佳组织)的本质