子查询vs联接

时间:2020-03-06 14:48:02  来源:igfitidea点击:

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

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

解决方案

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

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

通常情况下,in和Join可以使用相同的执行计划来实现,因此,在它们之间进行更改通常可以实现零加速。

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

优化器做得不好。通常,它们可以进行转换而没有任何差异,优化器可以做到这一点。

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

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

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

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

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

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

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

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

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

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

做这个:

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

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

在对查询数据集运行查询之前,优化器会尝试以一种可以尽快从结果集中删除元组(行)的方式来组织查询。通常,当我们使用子查询(尤其是坏查询)时,除非外部查询开始运行,否则无法从结果集中删除元组。

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

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

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

新的优化器会将这种子查询转换为联接。