子查询vs连接

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

where id in (select id from ... ) 

重构后的查询运行速度大约快100倍。 (约50秒〜0.3)我期望有一个改善,但任何人都可以解释为什么这么激烈? where子句中使用的列全部编入索引。 SQL是否每行执行一次where子句中的查询?

更新 – 解释结果:

区别在于“where id in()”查询的第二部分 –

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

vs 1索引行join:

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

“相关的子查询”(即where条件依赖于从包含查询的行获得的值)将针对每行执行一次。 一个不相关的子查询(其中where条件独立于包含的查询)将在开始时执行一次。 SQL引擎自动进行这种区分。

但是,是的,解释计划会给你肮脏的细节。

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

这是一个在MySQL 6.0中如何评估子查询的例子。

新的优化器将把这种子查询转换成连接。

运行每个版本的解释计划,它会告诉你为什么。

在针对通过查询优化器放置的数据集运行查询之前,优化器试图以这样的方式组织查询,即它可以尽可能快地从结果集中移除尽可能多的元组(行)。 通常当你使用子查询(尤其是坏的)时,元组不能被修剪出结果集,直到外部查询开始运行。

在看到这个查询之后,很难说出原来那么糟糕,但我的猜测是优化器不能做得更好。 运行“解释”将显示检索数据的优化器方法。

通常,优化器的结果是无法确定子查询是否可以作为联接来执行,在这种情况下,它会为表中的每个logging执行子查询,而不是将子查询中的表联接到正在查询的表。 一些更“企业”的数据库在这方面更好,但他们有时候还是会错过的。

这个问题有点泛泛,所以这是一个普遍的答案:

基本上,当MySQL有大量的行进行sorting时,查询需要更长的时间。

做这个:

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

我认为,看到MySQL对这些查询的解释的差异将成为每个人的学习体验。

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

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

在哪里连接 通常可以使用相同的执行计划来实现,因此通常在它们之间改变的速度是零。

优化器没有做得很好。 通常他们可以转换没有任何区别,优化器可以做到这一点。

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

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

使用子查询,您必须为每个结果重新执行第二个SELECT,每个执行通常返回1行。

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

与IN子句不同的是子查询,尽pipe连接至less是Oracle SQL引擎的基础,并且运行速度非常快。

从参考手册中获取( 14.2.10.11将子查询重写为连接 ):

LEFT [OUTER] JOIN可以比等效的子查询更快,因为服务器可能能够更好地优化它 – 这个事实并不是仅针对MySQL服务器。

所以子查询可以比左[OUTER] JOINS慢。