考虑可伸缩性时,为什么连接不好?

为什么join不好或“慢”。 我知道我多听了一次。 我发现这个报价

问题在于连接速度相对较慢,特别是在非常大的数据集上,如果速度慢,您的网站速度会变慢。 将所有这些单独的信​​息从磁盘上分离出来并把它们放在一起需要很长时间。

资源

我一直认为他们的速度特别快,当查找一个PK。 他们为什么“缓慢”?

join两个独立的数据源相对较慢,至less与未join数据源相比。 但请记住,替代scheme是根本不再有两个单独的数据; 你必须把两个不同的数据点放在同一个logging中。 你不能把两个不同的数据结合在一起,而不会在某个地方产生任何后果,所以确保你理解这个权衡。

好消息是现代关系数据库擅长连接。 一个好的数据库你不应该认为连接速度慢。 该数据库提供了多种方式来接收原始连接并使其更快:

  • join一个代理键(autonumer / identity列)而不是一个自然键。 这意味着在连接操作中比较小(因此更快)
  • 索引
  • 物化/索引视图(将其视为预先计算的连接或pipe理的非归一化)
  • 计算列。 您可以使用它来散列或以其他方式预先计算连接的关键字列,这样对连接进行复杂的比较现在会小得多,并且可能会进行预先编制索引。
  • 表分区(通过将负载分散到多个磁盘,或将表扫描限制到分区扫描的方式来帮助处理大数据集)
  • OLAP(预先计算某些types的查询/连接的结果,这并不完全正确,但您可以将其视为generics非规范化)

我会尽可能地说关系数据库存在的主要原因是让你有效地连接 * 。 这当然不仅仅是存储结构化数据(你可以使用像csv或xml这样的平面文件结构)。 我列出的一些选项甚至可以让你完全build立你的连接,所以结果已经完成,然后再发出查询 – 就像你已经非规范化的数据(承认以较慢的写操作为代价)。

如果你有一个缓慢的联接,你可能没有正确使用你的数据库。

只有在这些其他技术失败后才能进行解除归一化。 而唯一可以真正判断“失败”的方法是制定有意义的绩效目标和衡量目标。 如果你还没有测量,那么现在想去除归一化还为时过早。

*就是说,作为不同于表的集合的实体存在。 真正的rdbms的另一个原因是安全的并发访问。

连接可以比通过反规范化避免它们慢,但是如果使用正确(连接具有适当索引的列等), 它们本身并不慢

如果devise良好的数据库架构出现性能问题,则可以考虑采用反归一化技术。

文章说,与没有联接相比,它们很慢。 这可以通过非规范化来实现。 所以在速度和正常化之间有一个折衷。 不要忘记过早的优化也:)

terrabyte大小的数据库的人仍然使用联接,如果他们能够让他们的工作performance明智,那么你也可以。

有很多原因不能被分类。 首先,select查询的速度不是数据库唯一或甚至主要关心的问题。 数据的完整性是首先关心的问题。 如果你反规范化,那么你必须采取一些技术来保持数据非规范化,因为父数据发生了变化。 因此,假设您将客户端名称存储在所有表中,而不是joinclient_Id上的客户端表。 现在,当客户的名字发生变化(100%的机会,一些客户的名字会随着时间而改变),现在你需要更新所有的子logging来反映这种变化。 如果你这样做了级联更新,你有一百万的儿童logging,你认为这将是多快,有多less用户会遇到locking问题和工作延误,而事情发生? 更进一步,大多数因为“连接速度慢”而非规范化的人对数据库的了解不够充分,以确保其数据完整性得到保护,并且由于完整性如此糟糕,通常最终导致数据库具有不可用的数据。

非规范化是一个复杂的过程,需要对数据库性能和完整性有透彻的了解,才能正确完成。 除非你有这样的专业知识,否则不要企图去规范化。

如果你做了几件事情,联接是相当快的。 首先使用sugorggate键,int连接几乎是最快的连接。 其次总是索引外键。 使用派生表或连接条件来创build要过滤的较小数据集。 如果你有一个庞大的非常复杂的数据库,那么聘请一个在分配和pipe理大型数据库方面有经验的专业数据库人员。 有很多技术来提高性能,而不是摆脱连接。

如果你只是需要查询function,那么你可以devise一个数据仓库,它可以被非规范化,并通过一个ETL工具(对速度进行了优化)而不是用户数据input来填充。

如果连接速度很慢

  • 数据索引不当
  • 结果很差的过滤
  • join查询写得不好
  • 数据集非常庞大和复杂

所以,事实上,数据越大,查询所需的处理就越多,但检查和处理前三个选项往往会产生很好的结果。

您的来源提供了非规范化作为一个选项。 只要你用尽了更好的select,这就好了。

首先,关系数据库存在的理由是能够模拟实体之间的关系。 联结只是我们穿过这些关系的机制。 他们当然是以一个象征性的代价来进行的,但是如果没有连接,就没有理由拥有一个关系数据库。

在学术界,我们学习各种常规forms(第一,第二,第三,博伊斯 – 科德等),并学习不同types的键(主要的,外来的,替代的,独特的等等)这些东西装在一起来devise一个数据库。 我们学习SQL的基本知识以及操作结构和数据(DDL和DML)。

在企业界,许多学术成果显然比我们所相信的要less得多。 一个完美的例子是主键的概念。 在学术上,它是属性(或属性的集合),唯一标识表中的一行。 所以在很多问题领域,合适的学术主键是由3或4个属性组成的。 然而,现代企业界几乎所有人都使用自动生成的顺序整数作为表的主键。 为什么? 两个原因。 首先是因为当你将FK移植到所有的地方时,它会使模型变得更加清洁。 这个问题的第二个也是最相关的,就是通过连接检索数据在一个整数上比在4个varchar列上更快,更高效(正如一些人已经提到的那样)。

现在我们来深入一点,深入两个具体的现实世界数据库的子types。 第一种types是事务数据库。 这是许多电子商务或内容pipe理应用程序驱动现代网站的基础。 使用事务数据库,您正在大量优化“事务吞吐量”。 大多数商业或内容应用程序必须平衡查询性能(从某些表)与插入性能(在其他表),虽然每个应用程序将有其独特的业务驱动的问题来解决。

第二种types的现实世界数据库是报告数据库。 这几乎专门用于汇总业务数据并生成有意义的业务报告。 它们的形状通常与生成数据的事务数据库不同,它们针对批量数据加载(ETL)的速度以及大型或复杂数据集的查询性能进行了高度优化。

在每种情况下,开发人员或DBA都需要仔细平衡function和性能曲线,并且在方程两边都有很多性能提升的技巧。 在Oracle中,您可以执行所谓的“解释计划”,以便您可以具体了解查询是如何被parsing和执行的。 您正在寻求最大化数据库正确使用索引。 一个真正令人讨厌的禁忌是将函数放在查询的where子句中。 每当你这样做的时候,你保证Oracle不会在这个特定的列上使用任何索引,你可能会在解释计划中看到完整或部分的表扫描。 这只是一个具体的例子,说明如何编写一个查询,结果很慢,而且与连接没有任何关系。

当我们谈论表扫描时,他们显然影响查询速度与表的大小成比例。 100行的全表扫描甚至不明显。 在一个拥有1亿行的表上运行相同的查询,下个星期你需要返回。

我们来谈谈正常化一分钟。 这是另一个主要积极的学术话题,可以过度强调。 大多数时候,当我们谈论规范化时,我们的意思是通过将重复数据放入自己的表格并迁移FK来消除重复数据。 人们通常会跳过2NF和3NF描述的整个依赖关系。 然而,在极端的情况下,拥有一个完美的BCNF数据库是完全可能的,这个数据库非常庞大,而且完全可以用来编写代码,因为它是如此规范的。

那么我们在哪里平衡? 没有一个最好的答案。 所有更好的答案往往是在简单的结构维护,数据维护的简易性和代码创build/维护的简易性之间进行折衷。 一般来说,重复数据越less越好。

那么为什么联接有时慢? 有时候这是糟糕的关系devise。 有时候索引是无效的。 有时候这是一个数据量问题。 有时候这是一个可怕的书面查询。

对不起,这样一个冗长的回答,但我感到不得不围绕我的意见提供一个更有趣的背景,而不是只是响起4弹头的反应。

如果需要扫描来自每一边的大部分logging,连接速度可能会变慢。

喜欢这个:

SELECT SUM(transaction) FROM customers JOIN accounts ON account_customer = customer_id 

即使在account_customer上定义了索引,仍然需要扫描后者中的所有logging。

对于这个查询列表,体面优化器甚至不会考虑索引访问path,而是进行HASH JOINMERGE JOIN

请注意,对于这样的查询:

 SELECT SUM(transaction) FROM customers JOIN accounts ON account_customer = customer_id WHERE customer_last_name = 'Stellphlug' 

这个连接最有可能是快速的:首先, customer_last_name上的一个索引将被用于过滤所有的Stellphlug(当然不是很多),然后对每个Stellphlug发出一个索引扫描account_customer来查找他的事务。

尽pipe这些accountscustomers可能有数十亿条logging,但实际上只有less数logging需要扫描。

连接确实需要额外的处理,因为他们必须查看更多的文件和更多的索引来将数据“连接”在一起。 但是,“非常大的数据集”是相对的。 什么是大的定义? 我是JOIN的例子,我认为它是一个大的结果集的参考,而不是整个数据集。

大多数数据库可以非常快速地处理一个查询,从主表中select5条logging,并为每条logging从相关表中join5条logging(假设正确的索引就位)。 这些表格可以有数亿个logging,甚至数十亿个logging。

一旦结果集开始增长,事情就会放缓。 使用相同的例子,如果主表导致100Klogging,那么将会有500K“join”logging需要被发现。 只要将数据从数据库中拖出来就会增加延迟。

不要回避JOIN,只要知道在数据集变得非常大时你可能需要优化/非规范化。

连接被认为是可扩展性的反作用力,因为它们通常是瓶颈,不能容易地分布或并行。

正确devise的表格包含正确的标记和正确的书面查询不总是很慢。 你曾听说过:

为什么join不好或“慢”

不知道他们在说什么! 大多数join将会非常快。 如果你必须一次join许多行,与非规范化的表相比,你可能会受到一些打击,但是这可以追溯到正确devise的表格,知道何时去规范化和什么时候不去。 在庞大的报表系统中,打破非规范化表格中的数据报表,甚至创build一个数据仓库。 在交易繁重的系统中规范化表格。

Joins are fast. 连接应该被认为是一个标准的做法,一个正确的数据库模式。 连接允许您以有意义的方式join不同组的数据。 不要害怕join。

需要注意的是,您必须了解规范化,join和正确使用索引。

谨防过早优化,因为所有开发项目的头号失败正在赶上最后期限。 一旦你完成了这个项目,并且你明白了权衡,如果你能certificate这一点,你就可以违反规则。

确实,随着数据集大小的增加,连接性能会非线性地降低。 因此,它不像单表查询那么好,但它仍然有缩放。

一只鸟没有翅膀飞得更快,但是只能直下。

另外从你引用的文章:

许多规模巨大的网站拥有数十亿条logging,数十字节的数据,数以千计的同时在线的用户,以及每天数百万的查询正在使用分片scheme,有些甚至提倡非规范化作为架构数据层的最佳策略。

除非你是一个非常大的网站,否则你可能不需要担心这个复杂程度。

与数据库完成所有这些工作相比,它更容易出错,但是您甚至可以扩展甚至是最高端数据库所能处理的数据。

这篇文章正在讨论像Ebay这样的超级网站。 在这种使用级别下,你可能不得不考虑纯粹的vanilla关系数据库pipe理以外的事情。 但是,在“正常”的业务过程中(拥有数千用户和数百万条logging的应用程序),这些更加昂贵,更容易出错的方法是矫枉过正的。

根据连接生成的临时数据量可能会很大。

举个例子,这里的一个数据库有一个通用的searchfunction,其中所有的字段都是可选的。 search例程在search开始之前在每个表上进行了连接。 这在一开始就运行良好。 但是,现在主桌已经有超过一千万行了…并不多。 现在search需要30分钟或更长时间。

我的任务是优化search存储过程。

我做的第一件事情是,如果主表中的任何字段都被search,我只在这些字段上做了一个select到临时表。 那么,在进行其余的search之前,我把所有的表格都join了临时表格。 search其中一个主表字段现在所用的时间less于10秒。

如果没有主表字段被开始search,我会为其他表做类似的优化。 当我完成时,没有search需要超过30秒,大部分不到10。

SQL服务器的CPU使用率也走向了。

尽pipe连接(大概归因于规范化的devise)对于数据检索显然比从单个表中读取要慢,但是对于数据创build/更新操作来说,非规范化数据库可能会很慢,因为整个事务的占用空间不会很小。

在规范化的数据库中,一块数据只能存在一个地方,所以更新的占用空间将尽可能小。 在一个非规范化的数据库中,多行或跨表中的同一列可能需要更新,这意味着占用面积会更大,并且可能会增加锁和死锁。

那么,是的,从一个非规范化的表中select行(假设你的查询的体面索引)可能会更快,select连接几个表构造的行,特别是如果连接没有有效的索引可用。

文章中引用的例子 – Flickr和eBay – 是例外情况下的国际海事组织,所以有(和值得)特殊的回应。 作者特别提出缺乏RI和文章中重复数据的程度。

大多数应用程序(也是IMO)都从RDBMS提供的validation和减less重复中获益。

如果做得太慢,他们会变得很慢。 例如,如果您在join时select了“select*”,您将需要一些时间才能收回东西。 但是,如果您仔细select从每个表中返回的列,并且具有适当的索引,则应该没有问题。