JOIN查询比几个查询更快吗?(您运行主查询,然后根据主查询的结果运行许多其他SELECT)
我问,因为加入它们会使我的应用程序的设计变得复杂
如果它们更快,那么任何人都可以近似粗略估计多少?如果它是1.5倍我不在乎,但如果它是10倍我想我做.
对于内部联接,单个查询是有意义的,因为您只获得匹配的行.对于左连接,多个查询要好得多......看看我做的以下基准测试:
单个查询,包含5个联接
查询:8.074508秒
结果大小:2268000
连续5次查询
合并查询时间:0.00262秒
结果大小:165(6 + 50 + 7 + 12 + 90)
.
请注意,我们在两种情况下都得到相同的结果(6 x 50 x 7 x 12 x 90 = 2268000)
left join使用冗余数据指数级地增加内存.
如果您只进行两个表的连接,则内存限制可能不会那么糟糕,但通常是三个或更多,并且它变得值得进行不同的查询.
作为旁注,我的MySQL服务器就在我的应用服务器旁边......所以连接时间可以忽略不计.如果你的连接时间是几秒钟,那么也许有一个好处
坦率
这太模糊了,无法给出与您的具体案例相关的答案.这取决于很多事情.Jeff Atwood(这个网站的创始人)实际上写过这个.但是,在大多数情况下,如果你有正确的索引,并且你正确地进行了JOIN,那么一次旅行通常比几次更快.
实际上,我自己也在寻找答案,在阅读了给定的答案之后,我只能同意比较数据库查询性能的最佳方法是获取真实世界的数字,因为有很多变量需要考虑但是,我也认为比较它们之间的数字几乎在所有情况下都没有好处.我的意思是,数字应始终与可接受的数字进行比较,绝对不能相互比较.
我可以理解,如果一种查询方式需要0.02秒而另一种需要20秒,这是一个巨大的差异.但是,如果一种查询方式需要0.0000000002秒,而另一种方法需要0.0000002秒呢?在这两种情况下,一种方式比另一种方式快1000倍,但在第二种情况下它真的仍然"惊人"吗?
我亲眼看到它的底线:如果它表现良好,那就选择简单的解决方案.
快速测试是从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);
对于50,000次读取,两种选择方法花费3.7秒,而在家用慢速计算机上,JOIN花费2.0秒.INNER JOIN和LEFT JOIN并没有什么区别.获取多行(例如,使用IN SET)产生类似的结果.
构建单独的查询和连接,然后为每个查询和连接计时 - 没有什么比现实世界的数字更有帮助.
然后更好 - 在每个查询的开头添加"EXPLAIN".这将告诉您MySQL使用多少个子查询来回答您的数据请求,以及为每个查询扫描的行数.
真正的问题是:这些记录是一对一关系还是一对多关系?
TLDR答案:
如果一对一,请使用JOIN
声明.
如果是一对多,则使用一个(或多个)SELECT
语句与服务器端代码优化.
为什么以及如何使用SELECT进行优化
SELECT
基于一对多关系在大型记录组上进行(使用多个查询而不是连接)可以产生最佳效率,因为JOIN
存在指数性内存泄漏问题.获取所有数据,然后使用服务器端脚本语言对其进行排序:
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"
在这里,我将在一个选择语句中获取所有记录.这比JOIN
将要获得一小组这些记录(一次一个)作为另一个查询的子组件要好.然后我用服务器端代码解析它看起来像......
Address[] = $address; } ?>
何时不使用JOIN进行优化
JOIN
基于与一个记录的一对一关系的大量记录产生与多个SELECT
语句相比的最佳效率,一个接一个地获得下一个记录类型.
但是JOIN
在获得具有一对多关系的记录时效率很低.
示例:数据库博客有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与其2个竞争对手进行了基准测试:
N + 1个查询
2个查询,第二个查询使用a WHERE IN(...)
或同等查询
其结果是显而易见的:在MySQL,JOIN
是多快。N + 1个查询会大大降低应用程序的性能:
也就是说,除非您选择很多记录,这些记录都指向极少数不同的外来记录。这是极端情况的基准:
除非您要加入多对多关系(在这种情况下,外键在另一个表上,并且您要多次复制主表数据),否则在典型的应用程序中几乎不可能发生这种情况。
带走:
对于一对一关系,请始终使用 JOIN
对于多对多关系,第二个查询可能更快
有关更多信息,请参见我在Medium上的文章。
与开发人员复杂性相比,根据数据库的复杂性,执行许多SELECT调用可能更简单.
尝试针对JOIN和多个SELECTS运行一些数据库统计信息.查看在您的环境中JOIN是否比SELECT更快/更慢.
然后,如果将其更改为JOIN将意味着额外的一天/周/月的开发工作,我会坚持使用多个SELECT
干杯,
BLT
根据我的经验,我发现运行多个查询通常会更快,特别是在检索大型数据集时.
当从另一个应用程序(例如PHP)与数据库进行交互时,存在一个到服务器的一次访问的争论.
还有其他方法可以限制对服务器的访问次数,并且仍然运行多个查询,这些查询通常不仅更快,而且还使应用程序更易于阅读 - 例如mysqli_multi_query.
在SQL方面,我不是新手,我认为开发人员有一种趋势,特别是初级人员花费大量时间尝试编写非常聪明的连接,因为它们看起来很聪明,而实际上有很多智能方法可以提取看起来很简单的数据简单.
最后一段是个人意见,但我希望这会有所帮助.我确实同意其他人,但是谁说你应该做基准测试.这两种方法都不是银弹.