217

JOIN 查询比几个查询快吗?(您运行主查询,然后根据主查询的结果运行许多其他 SELECT)

我问是因为加入它们会使我的应用程序设计复杂化很多

如果它们更快,任何人都可以粗略地估计多少?如果是 1.5 倍,我不在乎,但如果是 10 倍,我想我会。

4

14 回答 14

117

对于内部联接,单个查询是有意义的,因为您只能获得匹配的行。对于左连接,多个查询要好得多......看看我做的以下基准:

  1. 具有 5 个连接的单个查询

    查询:8.074508 秒

    结果大小:2268000

  2. 连续 5 个查询

    组合查询时间:0.00262 秒

    结果大小:165(6 + 50 + 7 + 12 + 90)

.

请注意,我们在两种情况下得到相同的结果(6 x 50 x 7 x 12 x 90 = 2268000)

左连接使用冗余数据成倍增加内存。

如果你只连接两个表,内存限制可能不会那么糟糕,但通常是三个或更多,它变得值得不同的查询。

附带说明一下,我的 MySQL 服务器就在我的应用程序服务器旁边……所以连接时间可以忽略不计。如果您的连接时间在几秒钟内,那么也许有好处

坦率

于 2011-05-03T21:59:42.297 回答
95

这太模糊了,无法为您提供与您的具体案例相关的答案。这取决于很多事情。杰夫阿特伍德(本网站的创始人)实际上写过这个。但是,在大多数情况下,如果您拥有正确的索引并且正确地执行了 JOIN,则执行 1 次旅行通常比执行几次旅行要快。

于 2009-07-01T02:27:07.243 回答
50

这个问题很老,但缺少一些基准。我将 JOIN 与它的 2 个竞争对手进行了基准测试:

  • N+1 个查询
  • 2 个查询,第二个使用 aWHERE IN(...)或等效项

结果很清楚:在 MySQL 上,JOIN速度快得多。N+1 次查询会大大降低应用程序的性能:

加入 vs WHERE IN vs N+1

也就是说,除非您选择大量指向极少数不同的外来记录的记录。这是极端情况的基准:

JOIN vs N+1 - 所有记录指向同一个外部记录

这在典型应用程序中不太可能发生,除非您要加入一对多关系,在这种情况下,外键在另一个表上,并且您要多次复制主表数据。

带走:

  • 对于 * 对一的关系,请始终使用JOIN
  • 对于 * 对多的关系,第二个查询可能会更快

有关更多信息,请参阅我在 Medium 上的文章

于 2019-01-09T17:29:10.027 回答
23

实际上,我自己是在寻找这个问题的答案,在阅读了给定的答案后,我只能同意比较数据库查询性能的最佳方法是获取真实世界的数字,因为要考虑的变量很多但是,我也认为比较它们之间的数字几乎在所有情况下都没有好处。我的意思是,这些数字应始终与可接受的数字进行比较,绝对不能相互比较。

我可以理解,如果一种查询方式需要 0.02 秒,而另一种查询方式需要 20 秒,这是一个巨大的差异。但是,如果一种查询方式需要 0.0000000002 秒,而另一种需要 0.0000002 秒呢?在这两种情况下,一种方式比另一种方式快 1000 倍,但在第二种情况下它真的仍然“惊人”吗?

我个人认为的底线是:如果它表现良好,请选择简单的解决方案。

于 2010-07-07T08:01:29.207 回答
17

真正的问题是:这些记录是一对一关系还是一对多关系

TLDR 答案:

如果是一对一的,请使用JOIN语句。

如果是一对多,则使用一个(或多个)SELECT带有服务器端代码优化的语句。

为什么以及如何使用 SELECT 进行优化

SELECT'ing(使用多个查询而不是连接)基于一对多关系对大量记录产生最佳效率,因为JOIN'ing 存在指数内存泄漏问题。抓取所有数据,然后使用服务器端脚本语言对其进行整理:

SELECT * FROM Address WHERE Personid IN(1,2,3);

结果:

Address.id : 1            // First person and their address
Address.Personid : 1
Address.City : "Boston"

Address.id : 2            // First person's second address
Address.Personid : 1
Address.City : "New York"

Address.id : 3            // Second person's address
Address.Personid : 2
Address.City : "Barcelona"

在这里,我在一个 select 语句中获取所有记录。这比JOIN, 它将获得一小组这些记录,一次一个,作为另一个查询的子组件。然后我用看起来像...的服务器端代码解析它

<?php
    foreach($addresses as $address) {
         $persons[$address['Personid']]->Address[] = $address;
    }
?>

何时不使用 JOIN 进行优化

JOIN'基于与单个记录的一对一关系的大量记录与多个SELECT语句相比产生最佳效率,一个接一个地获得下一个记录类型。

但是JOIN在获取具有一对多关系的记录时效率低下。

示例:数据库 Blogs 有 3 个感兴趣的表,Blogpost、Tag 和 Comment。

SELECT * from BlogPost
LEFT JOIN Tag ON Tag.BlogPostid = BlogPost.id
LEFT JOIN Comment ON Comment.BlogPostid = BlogPost.id;

如果有 1 篇博文、2 个标签和 2 条评论,您将得到如下结果:

Row1: tag1, comment1,
Row2: tag1, comment2,
Row3: tag2, comment1,
Row4: tag2, comment2,

注意每条记录是如何复制的。好的,所以,2 个评论和 2 个标签是 4 行。如果我们有 4 个评论和 4 个标签怎么办?你没有得到 8 行——你得到 16 行:

Row1: tag1, comment1,
Row2: tag1, comment2,
Row3: tag1, comment3,
Row4: tag1, comment4,
Row5: tag2, comment1,
Row6: tag2, comment2,
Row7: tag2, comment3,
Row8: tag2, comment4,
Row9: tag3, comment1,
Row10: tag3, comment2,
Row11: tag3, comment3,
Row12: tag3, comment4,
Row13: tag4, comment1,
Row14: tag4, comment2,
Row15: tag4, comment3,
Row16: tag4, comment4,

添加更多的表、更多的记录等,问题将迅速膨胀到数百行,这些行都充满了大部分冗余数据。

这些重复的成本是多少?内存(在 SQL 服务器和尝试删除重复项的代码中)和网络资源(在 SQL 服务器和您的代码服务器之间)。

来源:https ://dev.mysql.com/doc/refman/8.0/en/nested-join-optimization.html ;https://dev.mysql.com/doc/workbench/en/wb-relationship-tools.html

于 2016-03-22T01:02:28.103 回答
16

做了一个快速测试,从 50,000 行表中选择一行,并从 100,000 行表中加入一行。基本上看起来像:

$id = mt_rand(1, 50000);
$row = $db->fetchOne("SELECT * FROM table1 WHERE id = " . $id);
$row = $db->fetchOne("SELECT * FROM table2 WHERE other_id = " . $row['other_id']);

对比

$id = mt_rand(1, 50000);
$db->fetchOne("SELECT table1.*, table2.*
    FROM table1
    LEFT JOIN table1.other_id = table2.other_id
    WHERE table1.id = " . $id);

两种选择方法需要 3.7 秒才能读取 50,000 次,而在我家的慢速计算机上 JOIN 需要 2.0 秒。INNER JOIN 和 LEFT JOIN 没有区别。获取多行(例如,使用 IN SET)产生了类似的结果。

于 2013-07-05T02:43:22.100 回答
8

构建单独的查询和连接,然后对它们中的每一个进行计时——没有什么比真实世界的数字更有帮助了。

然后更好 - 在每个查询的开头添加“EXPLAIN”。这将告诉您 MySQL 使用多少子查询来回答您的数据请求,以及为每个查询扫描了多少行。

于 2009-07-01T02:28:21.607 回答
6

根据与开发人员复杂性相比数据库的复杂性,执行许多 SELECT 调用可能更简单。

尝试针对 JOIN 和多个 SELECTS 运行一些数据库统计信息。查看在您的环境中,JOIN 是否比 SELECT 快/慢。

再说一次,如果将其更改为 JOIN 将意味着额外的一天/一周/一个月的开发工作,我会坚持使用多个 SELECT

干杯,

BLT

于 2009-07-01T02:29:34.977 回答
6

根据我的经验,我发现运行多个查询通常更快,尤其是在检索大型数据集时。

当从另一个应用程序(例如 PHP)与数据库交互时,存在一次访问服务器多于多次的论点。

还有其他方法可以限制对服务器的访问次数,并且仍然运行多个查询,这些查询通常不仅更快,而且使应用程序更易于阅读 - 例如 mysqli_multi_query。

说到 SQL,我不是新手,我认为开发人员,尤其是初级开发人员倾向于花费大量时间尝试编写非常聪明的连接,因为它们看起来很聪明,而实际上有一些聪明的方法可以提取看起来很聪明的数据简单的。

最后一段是个人意见,但我希望这会有所帮助。我确实同意其他人的观点,尽管他们说你应该进行基准测试。这两种方法都不是灵丹妙药。

于 2012-06-24T16:37:13.283 回答
4

在吞吐量方面会更快吗?大概。但它也可能一次锁定更多数据库对象(取决于您的数据库和架构),从而降低并发性。根据我的经验,人们经常被“更少的数据库往返”论点误导,而实际上在大多数数据库位于同一 LAN 上的 OLTP 系统上,真正的瓶颈很少是网络。

于 2009-10-30T09:17:52.030 回答
4

是否应该使用连接首先是关于连接是否有意义。只有在这一点上才需要考虑性能,因为几乎所有其他情况都会导致性能明显下降

性能差异在很大程度上与您查询的信息的相关程度有关。连接可以工作,当数据相关并且您正确索引内容时它们会很快,但它们通常会导致一些冗余,有时会导致超出需要的结果。如果您的数据集不直接相关,将它们放在单个查询中将导致所谓的笛卡尔积(基本上是所有可能的行组合),这几乎不是您想要的。

这通常是由多对一对多关系引起的。例如,HoldOffHunger 的回答提到了对帖子、标签和评论的单个查询。评论与帖子相关,标签也是如此……但标签与评论无关。

+------------+     +---------+     +---------+
|  comment   |     |   post  |     |  tag    |
|------------|*   1|---------|1   *|---------|
| post_id    |-----| post_id |-----| post_id |
| comment_id |     | ...     |     | tag_id  |
| user_id    |     |         |     | ...     |
| ...        |     |         |     | ...     |
+------------+     +---------+     +---------+

在这种情况下,这无疑是至少两个单独的查询更好。如果您尝试加入标签和评论,因为两者之间没有直接关系,您最终会得到标签和评论的所有可能组合。many * many == manymany. 除此之外,由于帖子和标签不相关,您可以并行执行这两个查询,从而获得潜在收益。

不过,让我们考虑一个不同的场景:您希望将评论附加到帖子中,以及评论者的联系信息。

 +----------+     +------------+     +---------+
 |   user   |     |  comment   |     |   post  |
 |----------|1   *|------------|*   1|---------|
 | user_id  |-----| post_id    |-----| post_id |
 | username |     | user_id    |     | ...     |
 | ...      |     | ...        |     +---------+
 +----------+     +------------+

这是您应该考虑加入的地方。除了是一个更自然的查询之外,大多数数据库系统(包括 MySQL)都有很多聪明的人投入大量精力来优化查询,就像它一样。对于单独的查询,由于每个查询都依赖于前一个查询的结果,所以查询不能并行进行,总时间不仅变成了查询的实际执行时间,还变成了获取结果、筛选的时间通过它们获取下一个查询的 ID,将行链接在一起等。

于 2018-06-05T20:38:48.963 回答
2

这是一个包含 100 个有用查询的链接,这些查询在 Oracle 数据库中进行了测试,但请记住 SQL 是一个标准,Oracle、MS SQL Server、MySQL 和其他数据库之间的区别在于 SQL 方言:

http://javaforlearn.com/100-sql-queries-learn/

于 2016-12-15T03:32:22.990 回答
1

有几个因素意味着没有二元答案。什么最适合性能的问题取决于您的环境。顺便说一句,如果您的带有标识符的单选不是亚秒级的,那么您的配置可能有问题。

要问的真正问题是您想如何访问数据。单选支持后期绑定。例如,如果您只需要员工信息,则可以从员工表中进行选择。外键关系可用于稍后根据需要检索相关资源。选择已经有一个指向的键,所以它们应该非常快,你只需要检索你需要的东西。必须始终考虑网络延迟。

联接将一次检索所有数据。如果您正在生成报告或填充网格,这可能正是您想要的。在这种情况下,编译和优化的连接只会比单选快。请记住,临时连接可能没有那么快——您应该将它们编译(到存储过程中)。速度答案取决于执行计划,该计划详细说明了 DBMS 检索数据所采取的步骤。

于 2013-07-18T14:14:10.450 回答
0

是的,一个使用 JOINS 的查询会更快。尽管不知道您要查询的表的关系、数据集的大小或主键的位置,但几乎不可能说出速度有多快。

为什么不测试这两种情况,那么你肯定会知道......

于 2009-07-01T02:33:00.523 回答