JOIN查询是否比多个查询快?(运行主查询,然后根据主查询的结果运行许多其他select)
我这么问是因为加入它们会使我的应用程序的设计复杂化
如果它们快了,有人能大致估计出快了多少吗?如果是1.5倍,我不在乎,但如果是10倍,我就在乎。
JOIN查询是否比多个查询快?(运行主查询,然后根据主查询的结果运行许多其他select)
我这么问是因为加入它们会使我的应用程序的设计复杂化
如果它们快了,有人能大致估计出快了多少吗?如果是1.5倍,我不在乎,但如果是10倍,我就在乎。
当前回答
有几个因素,这意味着没有二元答案。什么对性能最好取决于您的环境。顺便说一下,如果带有标识符的单个选择不是次秒级的,那么您的配置可能有问题。
真正要问的问题是您希望如何访问数据。单个选择支持后期绑定。例如,如果您只想要员工信息,您可以从Employees表中进行选择。外键关系可用于在以后根据需要检索相关资源。选择已经有一个键指向,所以它们应该非常快,你只需要检索你需要的。必须始终考虑到网络延迟。
联接将一次检索所有数据。如果您正在生成一个报告或填充一个网格,这可能正是您想要的。在这种情况下,编译和优化的连接将比单一选择更快。请记住,Ad-hoc连接可能没有那么快——您应该将它们编译(到存储的proc中)。速度取决于执行计划,该计划详细说明了DBMS检索数据所采取的步骤。
其他回答
做了一个快速测试,从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']);
vs
$id = mt_rand(1, 50000);
$db->fetchOne("SELECT table1.*, table2.*
FROM table1
LEFT JOIN table1.other_id = table2.other_id
WHERE table1.id = " . $id);
在我的家用慢速电脑上,two select方法读取50,000次需要3.7秒,而JOIN方法需要2.0秒。INNER JOIN和LEFT JOIN没有区别。获取多行(例如,使用IN SET)会产生类似的结果。
根据数据库的复杂性与开发人员的复杂性的不同,执行多次SELECT调用可能更简单。
尝试对JOIN和多个select运行一些数据库统计信息。看看在您的环境中,JOIN是否比SELECT更快/更慢。
然后,如果将其更改为JOIN将意味着额外的一天/一周/一个月的开发工作,我将坚持使用多个select
欢呼,
BLT
有几个因素,这意味着没有二元答案。什么对性能最好取决于您的环境。顺便说一下,如果带有标识符的单个选择不是次秒级的,那么您的配置可能有问题。
真正要问的问题是您希望如何访问数据。单个选择支持后期绑定。例如,如果您只想要员工信息,您可以从Employees表中进行选择。外键关系可用于在以后根据需要检索相关资源。选择已经有一个键指向,所以它们应该非常快,你只需要检索你需要的。必须始终考虑到网络延迟。
联接将一次检索所有数据。如果您正在生成一个报告或填充一个网格,这可能正是您想要的。在这种情况下,编译和优化的连接将比单一选择更快。请记住,Ad-hoc连接可能没有那么快——您应该将它们编译(到存储的proc中)。速度取决于执行计划,该计划详细说明了DBMS检索数据所采取的步骤。
真正的问题是:这些记录是一对一的关系还是一对多的关系?
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要好,JOIN每次只获取一小组这样的记录,作为另一个查询的子组件。然后我用服务器端代码解析它,看起来像……
<?php
foreach($addresses as $address) {
$persons[$address['Personid']]->Address[] = $address;
}
?>
何时不使用JOIN进行优化
与多个SELECT语句相比,基于与单个记录的一对一关系连接一大组记录可以产生最佳效率,这些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
这个问题很老了,但是缺少一些基准。我对比了JOIN的两个竞争对手:
N + 1查询 2个查询,第二个查询使用WHERE IN(…)或等价的
结果很明显:在MySQL上,JOIN要快得多。N+1个查询会大大降低应用程序的性能:
也就是说,除非您选择了大量指向极少数不同的外部记录的记录。下面是极端情况下的基准测试:
在典型的应用程序中,这种情况不太可能发生,除非您正在连接一对多的关系,在这种情况下,外键在另一个表上,并且您多次复制主表数据。
导读:
对于*对1关系,总是使用JOIN 对于*对多的关系,第二个查询可能更快
更多信息请参阅我在Medium上的文章。