【发布时间】:2011-02-07 02:34:13
【问题描述】:
为什么连接不好或“慢”。我知道我不止一次听到过这个。我找到了这句话
问题是连接是相对的 慢,尤其是在非常大的数据上 套,如果他们很慢你 网站很慢。需要很长时间 得到所有这些单独的位 磁盘上的信息并将它们全部放入 再次在一起。
我一直认为他们很快,尤其是在查找 PK 时。为什么他们“慢”?
【问题讨论】:
为什么连接不好或“慢”。我知道我不止一次听到过这个。我找到了这句话
问题是连接是相对的 慢,尤其是在非常大的数据上 套,如果他们很慢你 网站很慢。需要很长时间 得到所有这些单独的位 磁盘上的信息并将它们全部放入 再次在一起。
我一直认为他们很快,尤其是在查找 PK 时。为什么他们“慢”?
【问题讨论】:
可扩展性是关于预计算(缓存)、扩展或将重复的工作缩减为最基本的工作,以最大限度地减少每个工作单元的资源使用。为了实现良好的扩展,您不需要在数量上做任何您不需要做的事情,并且您要确保尽可能高效地完成您实际做的事情。
在这种情况下,加入两个单独的数据源当然相对较慢,至少与不加入它们相比是这样,因为这是您需要在用户请求时实时完成的工作。
但请记住,替代方案不再有两个单独的数据;您必须将两个不同的数据点放在同一记录中。您无法在某处没有结果的情况下组合两个不同的数据,因此请确保您了解权衡取舍。
好消息是现代关系数据库擅长连接。您真的不应该认为使用良好的数据库连接会很慢。有许多可扩展性友好的方法来获取原始连接并使它们大大更快:
我想说存在关系数据库的主要原因是允许您有效地进行联接*。当然不仅仅是存储结构化数据(您可以使用 csv 或 xml 等平面文件结构来做到这一点)。我列出的一些选项甚至可以让您提前完全构建连接,因此在您发出查询之前结果已经完成 - 就像您对数据进行了非规范化(诚然以较慢的写入操作为代价)。
如果您的连接速度较慢,您可能没有正确使用您的数据库。
只有在这些其他技术失败后才能进行反规范化。真正判断“失败”的唯一方法是设定有意义的绩效目标并根据这些目标进行衡量。 如果你还没有测量,那么现在考虑去规范化还为时过早。
* 即,作为与单纯的表集合不同的实体存在。真正的 rdbms 的另一个原因是安全的并发访问。
【讨论】:
也来自您引用的文章:
许多拥有数十亿美元的超大型网站 记录,PB 级数据,许多 数以千计的同时用户,以及 每天数百万的查询是 使用分片方案,有些是 甚至提倡非规范化 架构的最佳策略 数据层。
和
除非你真的很大 您可能不需要的网站 担心这种复杂程度。
和
这比拥有 数据库完成所有这些工作,但你是 能够超越甚至 最高端的数据库可以处理。
本文讨论的是 Ebay 等大型网站。在这种使用级别上,您可能不得不考虑普通关系数据库管理以外的其他东西。但是在“正常”的业务过程中(具有数千个用户和数百万条记录的应用程序),那些更昂贵、更容易出错的方法是矫枉过正的。
【讨论】:
首先,关系数据库的存在理由(存在的理由)是能够对实体之间的关系进行建模。连接只是我们遍历这些关系的机制。当然,它们的成本确实很低,但是如果没有连接,就真的没有理由拥有一个关系数据库。
在学术界,我们学习各种范式(1st、2nd、3rd、Boyce-Codd 等),我们了解不同类型的键(主键、外键、备用键、唯一键等)。 ) 以及这些东西如何组合在一起来设计数据库。我们学习了 SQL 的基础知识以及操作结构和数据(DDL 和 DML)。
在企业界,许多学术结构的可行性远没有我们想象的那么大。一个完美的例子是主键的概念。从学术上讲,它是唯一标识表中一行的属性(或属性集合)。因此,在许多问题领域中,正确的学术主键是 3 或 4 个属性的组合。然而,现代企业界中的几乎每个人都使用自动生成的顺序整数作为表的主键。为什么?两个原因。首先是因为当您在各处迁移 FK 时,它使模型更加简洁。第二个也是与这个问题最密切相关的是,通过连接检索数据在单个整数上比在 4 个 varchar 列上更快、更有效(正如一些人已经提到的那样)。
现在让我们更深入地研究一下现实世界数据库的两个特定子类型。第一种类型是事务数据库。这是驱动现代网站的许多电子商务或内容管理应用程序的基础。使用事务数据库,您正在对“事务吞吐量”进行大量优化。大多数商业或内容应用程序必须平衡查询性能(来自某些表)和插入性能(在其他表中),尽管每个应用程序都有自己独特的业务驱动问题需要解决。
第二种真实世界数据库是报告数据库。这些几乎专门用于汇总业务数据并生成有意义的业务报告。它们的形状通常不同于生成数据的事务数据库,并且针对批量数据加载 (ETL) 的速度和大型或复杂数据集的查询性能进行了高度优化。
在每种情况下,开发人员或 DBA 都需要仔细平衡功能和性能曲线,并且在等式的两边都有很多提高性能的技巧。在 Oracle 中,您可以执行所谓的“解释计划”,以便具体了解查询是如何被解析和执行的。您正在寻求最大化数据库对索引的正确使用。一个非常讨厌的禁忌是将函数放在查询的 where 子句中。每当您这样做时,您就可以保证 Oracle 不会对该特定列使用任何索引,并且您可能会在解释计划中看到完整或部分表扫描。这只是一个具体示例,说明如何编写最终会变慢的查询,并且它与联接没有任何关系。
当我们谈论表扫描时,它们显然会影响查询速度与表的大小成正比。 100 行的全表扫描甚至都不明显。对具有 1 亿行的表运行相同的查询,您需要下周返回。
让我们先谈谈规范化。这是另一个可能被过度强调的积极的学术话题。大多数时候,当我们谈论规范化时,我们实际上是指通过将重复数据放入自己的表中并迁移 FK 来消除重复数据。人们通常会跳过 2NF 和 3NF 描述的整个依赖关系。然而在极端情况下,当然有可能拥有一个完美的 BCNF 数据库,该数据库非常庞大,并且是编写代码的完整野兽,因为它是如此规范化。
那么我们在哪里平衡呢?没有单一的最佳答案。所有更好的答案往往是在易于结构维护、易于数据维护和易于代码创建/维护之间做出某种折衷。一般来说,数据重复越少越好。
那么为什么连接有时很慢?有时它是糟糕的关系设计。有时它是无效的索引。有时这是数据量问题。有时这是一个可怕的书面查询。
很抱歉这么冗长的回答,但我觉得有必要在我的 cmets 周围提供一个更丰富的背景,而不是仅仅喋喋不休地回答 4 子弹。
【讨论】:
与通过反规范化避免它们相比,连接可能慢,但如果使用正确(在具有适当索引的列上连接等等)它们本身并不慢。
如果您精心设计的数据库架构出现性能问题,您可以考虑使用反规范化技术之一。
【讨论】:
Joins are fast. 连接应被视为具有适当规范化数据库模式的标准做法。联接允许您以有意义的方式联接不同的数据组。不要害怕加入。
需要注意的是,您必须了解规范化、连接和正确使用索引。
提防过早的优化,因为所有开发项目的第一大失败就是赶不上最后期限。一旦你完成了项目,并且了解了权衡,如果你能证明它是合理的,你就可以打破规则。
确实,随着数据集大小的增加,连接性能会非线性下降。因此,它的扩展性不如单表查询,但它仍然可以扩展。
没有翅膀的鸟飞得更快也是事实,但只能直下。
【讨论】:
嗯,是的,从一个非规范化表中选择行(假设您的查询有合适的索引)可能比选择通过连接多个表构建的行更快,特别是如果连接没有可用的有效索引。
文章中引用的示例 - Flickr 和 eBay - 是 IMO 的例外情况,因此有(并且值得)例外响应。作者在文章中特别指出了RI的缺失和数据重复的程度。
大多数应用程序 - 同样是 IMO - 受益于 RDBMS 提供的验证和减少重复。
【讨论】:
连接确实需要额外的处理,因为它们必须查看更多文件和更多索引才能将数据“连接”在一起。然而,“非常大的数据集”都是相对的。大的定义是什么?对于 JOIN,我认为它是对大型结果集的引用,而不是整个数据集。
大多数数据库可以非常快速地处理从主表中选择 5 条记录并为每条记录连接相关表中的 5 条记录的查询(假设有正确的索引)。这些表每个可以有数亿条记录,甚至数十亿条记录。
一旦您的结果集开始增长,事情就会放缓。使用相同的示例,如果主表产生 10 万条记录,那么将有 50 万条“连接”记录需要查找。只是从数据库中提取这么多数据并增加延迟。
不要避免 JOIN,只要知道当数据集变得“非常大”时您可能需要优化/反规范化。
【讨论】:
拥有 TB 级数据库的人仍然使用联接,如果他们能让它们在性能方面发挥作用,那么您也可以。
有很多理由不去规范化。首先,选择查询的速度并不是数据库的唯一甚至主要关注点。数据的完整性是首要关注的问题。如果您进行非规范化,那么您必须采用适当的技术来保持数据在父数据更改时进行非规范化。因此,假设您将客户端名称存储在所有表中,而不是在 client_Id 上加入客户端表。现在,当客户端的名称发生变化时(100% 的机会一些客户端的名称会随着时间而变化),现在您需要更新所有子记录以反映该变化。如果您这样做是为了进行级联更新并且您有一百万个子记录,那么您认为这将是多快以及有多少用户会遇到锁定问题和工作延迟?此外,由于“连接速度很慢”而进行非规范化的大多数人对数据库的了解不足,无法正确确保其数据完整性受到保护,并且由于完整性太差,通常最终会得到具有不可用数据的数据库。
非规范化是一个复杂的过程,如果要正确完成,需要对数据库性能和完整性有透彻的了解。除非您对员工有这样的专业知识,否则不要尝试去规范化。
如果你做几件事情,连接就足够快了。首先使用 suggorgate 键,int 连接几乎是最快的连接。其次总是索引外键。使用派生表或连接条件创建一个较小的数据集进行过滤。如果您有一个非常复杂的大型数据库,请聘请具有分区和管理大型数据库经验的专业数据库人员。有很多技术可以在不消除连接的情况下提高性能。
如果您只需要查询功能,那么是的,您可以设计一个可以非规范化的数据仓库,并通过 ETL 工具(针对速度进行了优化)而不是用户数据输入来填充。
【讨论】:
虽然连接(可能是由于规范化设计)对于数据检索显然比从单个表中读取要慢,但非规范化数据库对于数据创建/更新操作可能会很慢,因为整个事务的足迹不会最小。
在规范化数据库中,一条数据将只存在于一个位置,因此更新的占用空间将尽可能小。在非规范化数据库中,可能需要更新多行或跨表中的同一列,这意味着占用空间会更大,并且可能会增加锁定和死锁的机会。
【讨论】:
如果
,连接会很慢确实,数据集越大,查询所需的处理就越多,但检查和处理上述前三个选项通常会产生很好的结果。
您的来源提供了非规范化作为选项。只要您已经用尽了更好的选择,这很好。
【讨论】:
如果需要扫描来自每一方的大部分记录,则连接可能会很慢。
像这样:
SELECT SUM(transaction)
FROM customers
JOIN accounts
ON account_customer = customer_id
即使在account_customer 上定义了索引,仍然需要扫描来自后者的所有记录。
对于这个查询列表,体面的优化器可能甚至不会考虑索引访问路径,而是使用HASH JOIN 或MERGE JOIN。
请注意,对于这样的查询:
SELECT SUM(transaction)
FROM customers
JOIN accounts
ON account_customer = customer_id
WHERE customer_last_name = 'Stellphlug'
连接很可能会很快:首先,customer_last_name 上的索引将用于过滤所有 Stellphlug(当然数量不多),然后将针对 account_customer 发出索引扫描每个 Stellphlug 都可以找到他的交易。
尽管accounts 和customers 中可能有数十亿条记录,但实际上只有少数需要扫描。
【讨论】:
accounts(account_customer) 上定义了索引,大多数 RDBMS 将使用该索引来准确找出需要扫描 customers 数据库的哪些行。
HASH JOIN 会快得多,所以除了MySQL 之外的所有主要数据库都将使用它,这只会使customers 在嵌套循环中领先(因为它的大小更小)
正确设计的表包含正确的索引和正确编写的查询并不总是很慢。你在哪里听说过:
为什么连接不好或“慢”
不知道他们在说什么!!!大多数连接将非常快。如果您必须一次连接许多行,与非规范化表相比,您可能会受到打击,但这可以追溯到正确设计的表,知道何时进行非规范化以及何时不进行非规范化。在繁重的报表系统中,将非规范化表格中的数据分解为报表,甚至创建数据仓库。在事务繁重的系统中规范化表。
【讨论】:
根据连接,生成的临时数据量可能很大。
例如,这里的一个数据库具有通用搜索功能,其中所有字段都是可选的。搜索例程在搜索开始之前对每个表进行了连接。这在开始时运作良好。但是,现在主表有超过 1000 万行......不是那么多。现在搜索需要 30 分钟或更长时间。
我的任务是优化搜索存储过程。
我做的第一件事是,如果正在搜索主表的任何字段,我只对这些字段的临时表进行了选择。然后,在进行其余的搜索之前,我将所有表与该临时表连接起来。现在可以在不到 10 秒的时间内搜索其中一个主表字段。
如果没有开始搜索主表字段,我会对其他表进行类似的优化。完成后,搜索时间不会超过 30 秒,大多数都在 10 秒以下。
SQL 服务器的 CPU 利用率也下降了。
【讨论】:
联接被认为是与可扩展性相反的力量,因为它们通常是瓶颈,并且不能轻松分布或并行。
【讨论】:
如果做得草率,它们可能会很慢。例如,如果您在连接上执行“选择 *”,您可能需要一段时间才能恢复。但是,如果您仔细选择要从每个表返回的列,并使用适当的索引,应该没有问题。
【讨论】:
文章说,与没有连接相比,它们很慢。这可以通过非规范化来实现。所以在速度和标准化之间有一个权衡。不要忘记过早的优化:)
【讨论】: