子查询与联接


158

我重构了我们从另一家公司继承来的应用程序的缓慢部分,以使用内部联接而不是子查询,例如:

WHERE id IN (SELECT id FROM ...)

重构查询的运行速度提高了约100倍。(约50秒,约0.3秒),我期望有所改善,但是谁能解释为什么如此剧烈?where子句中使用的列均已建立索引。SQL是否在where子句中每行执行一次查询?

更新 -说明结果:

区别在于“(())中的id”查询的第二部分-

2   DEPENDENT SUBQUERY  submission_tags ref st_tag_id   st_tag_id   4   const   2966    Using where

vs 1带有连接的索引行:

    SIMPLE  s   eq_ref  PRIMARY PRIMARY 4   newsladder_production.st.submission_id  1   Using index


2
不能重复。该问题专门涉及显着的性能差异。另一个问题更笼统,关于每种方法的优缺点以及为什么一种方法似乎更受欢迎,是开放性的。
罗勒·布尔克

@simhumileco这没有改善,也没有区别,这与作者写的相反,并且那种对代码样式的编辑是不合适的。什么时候应该对代码进行编辑?
philipxy

@philipxy,您好,我无意干扰作者的想法,而只是为了使代码片段更易于阅读和编写。
simhumileco

Answers:


160

“相关子查询”(即,其中where条件取决于从包含查询的行获得的值的子查询)将为每一行执行一次。不相关的子查询(其中where条件独立于所包含查询的子查询)将在开始时执行一次。SQL引擎自动进行区分。

但是,是的,解释计划将为您提供肮脏的细节。


3
请注意,这DEPENDENT SUBQUERY意味着与“相关子查询”完全相同。
蒂莫

38

为每行运行一次子查询而联接发生在索引上。


5
我不认为这是真的。SQL引擎应该只运行一次子查询,并将结果用作列表。
dacracot

8
这取决于-如果子查询以某种方式与外部查询相关联(使用其数据),则会对每一行执行该查询。
qbeuek

4
在这种情况下,这可能是正确的,但总体而言,事实并非如此。
艾米B

1
OP EXPLAIN表示DEPENDENT SUBQUERY,这是此行为的最明显指标。
蒂莫,2016年


7

在每个版本上运行解释计划,它将告诉您原因。


6

在将查询通过查询优化器放入数据集之前,优化器尝试以这种方式组织查询,即它可以尽快从结果集中删除尽可能多的元组(行)。通常,当您使用子查询(尤其是坏查询)时,除非外部查询开始运行,否则无法从结果集中删除元组。

由于没有看到查询,很难说出原始查询有什么不好,但是我猜想那是优化器无法做得更好的事情。运行“解释”将为您显示用于检索数据的优化器方法。


4

查看每个查询的查询计划。

凡在加入通常使用相同的执行计划来实现,所以通常有零加速从他们之间发生变化。


3
哈哈,我<3 Sql减少了表决的难度,因为他们不知道如何读取查询计划。
艾米B


4

通常,优化器的结果是无法确定子查询可以作为联接执行,在这种情况下,它将为表中的每个记录执行子查询,而不是针对查询的表联接子查询中的表。一些更“主动”的数据库在此方面更好,但有时仍然会遗漏它。


4

这个问题有点笼统,所以这里是一个笼统的答案:

基本上,当MySQL有大量行要排序时,查询会花费更长的时间。

做这个:

对每个查询(加入的查询,然后是子查询的查询)运行一个EXPLAIN,并将结果发布在这里。

我认为看到MySQL对这些查询的解释有所不同将是每个人的学习经历。


4

where子查询必须为每个返回的行运行1个查询。内部联接只需要运行1个查询。


3

子查询可能正在执行“全表扫描”。换句话说,不使用索引并返回太多行,以至于主查询中的Where需要过滤掉。

只是没有具体细节的猜测,但这是常见的情况。


2

对于子查询,您必须为每个结果重新执行第二个SELECT,并且每次执行通常返回1行。

通过联接,第二个SELECT返回更多行,但是您只需执行一次即可。好处是现在您可以联接结果,联接关系是数据库应该擅长的。例如,也许优化器现在可以发现如何更好地利用索引。


2

尽管联接是至少Oracle的SQL引擎的基础,并且运行非常迅速,但它不是IN子句,而是子查询。


1
实际上并不是天生就糟糕的地方。
肖恩

2

摘自《参考手册》(14.2.10.11将子查询重写为联接):

LEFT [OUTER] JOIN可以比等效的子查询更快,因为服务器可能能够更好地对其进行优化-这不仅限于MySQL Server。

因此子查询可能比LEFT [OUTER] JOINS慢。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.