当前位置:  开发笔记 > 编程语言 > 正文

JOIN查询与多个查询

如何解决《JOIN查询与多个查询》经验,为你挑选了9个好方法。

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

我问,因为加入它们会使我的应用程序的设计变得复杂

如果它们更快,那么任何人都可以近似粗略估计多少?如果它是1.5倍我不在乎,但如果它是10倍我想我做.



1> 小智..:

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

    单个查询,包含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服务器就在我的应用服务器旁边......所以连接时间可以忽略不计.如果你的连接时间是几秒钟,那么也许有一个好处

坦率


如果我们抛开一个令人讨厌的小事实,即在他们正确的思想中没有人在5个表之间进行交叉连接(因为这个原因,在大多数情况下,它只是没有意义*),你的"基准"可能有一些优点.但是左边或内部连接是常态,通常是按键(使检索更快),并且数据的重复通常比你实现的要多得多*.*.
@cHao说谁?我只是查看了SMF和phpBB,看到了3个表之间的JOIN - 如果你添加插件或修改,他们可以很容易地添加到那里.任何类型的大型应用程序都有可能存在许多JOIN.可以说,写得不好/使用不当的ORM可能会加入它实际上并不需要的表(甚至可能是每个表).
@NathanAdams:左边和内部连接都不差.(事实上​​,如果你不是在这里和那里连接表,那你就错误地做了SQL.)我所说的是*交叉连接*,即使在两个表之间也几乎总是不受欢迎的,更不用说5 - 和这将是获得上面提到的完全伪造的"2268000"结果的唯一方法.
@cHao显然,您在发表第一条评论时尚未见过Magento
但是看看结果."结果大小:2268000"与"结果大小:165".我认为你对JOIN的减速是因为你的记录彼此之间有一对多的关系,而如果他们有一对一的关系,那么JOIN肯定会快得多,而且肯定不会有结果尺寸大于SELECT.

2> Paolo Bergan..:

这太模糊了,无法给出与您的具体案例相关的答案.这取决于很多事情.Jeff Atwood(这个网站的创始人)实际上写过这个.但是,在大多数情况下,如果你有正确的索引,并且你正确地进行了JOIN,那么一次旅行通常比几次更快.


我认为这取决于你对"更快"的定义...例如,由于网络开销,3个PK内连接可能比4个往返更快转,并且因为你需要停止并准备并发送每个查询后上一个查询完成.但是,如果要对负载下的服务器进行基准测试,则在大多数情况下,连接将比PK查询花费更多的CPU时间,并且通常也会导致更多的网络开销.
如果你在不同的键上加入3个或更多的表,通常数据库(即mysql)每个表只能使用一个索引,这意味着其中一个连接将是快速的(并使用索引),而其他连接将非常慢.对于多个查询,您可以优化要用于每个查询的索引.

3> Valentin Fla..:

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

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

我亲眼看到它的底线:如果它表现良好,那就选择简单的解决方案.


当然,这取决于你是否计划扩展.当Facebook开始时我很确定他们有这样的疑问,但是考虑到了扩展并且考虑了更有效但可能更复杂的解决方案.
哈哈,是的...因为在谷歌1纳秒的损失实际上相当于100亿亿美元......但这只是一个谣言.

4> 小智..:

快速测试是从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)产生类似的结果.



5> DreadPirateS..:

构建单独的查询和连接,然后为每个查询和连接计时 - 没有什么比现实世界的数字更有帮助.

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



6> HoldOffHunge..:

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

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



7> Benjamin..:

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

N + 1个查询

2个查询,第二个查询使用a WHERE IN(...)或同等查询

其结果是显而易见的:在MySQL,JOIN快。N + 1个查询会大大降低应用程序的性能:

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

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

带走:

对于一对一关系,请始终使用 JOIN

对于多对多关系,第二个查询可能更快

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



8> glasnt..:

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

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

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

干杯,

BLT



9> 小智..:

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

当从另一个应用程序(例如PHP)与数据库进行交互时,存在一个到服务器的一次访问的争论.

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

在SQL方面,我不是新手,我认为开发人员有一种趋势,特别是初级人员花费大量时间尝试编写非常聪明的连接,因为它们看起来很聪明,而实际上有很多智能方法可以提取看起来很简单的数据简单.

最后一段是个人意见,但我希望这会有所帮助.我确实同意其他人,但是谁说你应该做基准测试.这两种方法都不是银弹.

推荐阅读
mobiledu2402851203
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有