子查询与联接

我重构了从另一家公司继承的应用程序的一个较慢的部分,使用内部连接而不是子查询,比如:

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

Vs1带有连接的索引行:

    SIMPLE  s   eq_ref  PRIMARY PRIMARY 4   newsladder_production.st.submission_id  1   Using index
60481 次浏览

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

加入中,可以使用相同的执行计划来实现 一般来说,因此 一般来说在它们之间的更改没有加速。

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

优化器做得不是很好。通常,它们可以在没有任何差异的情况下进行转换,优化器可以做到这一点。

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

对于连接,第2个 SELECT 返回更多的行,但是您只需要执行一次。优点是现在您可以对结果进行连接,连接关系是数据库应该擅长的。例如,也许优化器现在就能发现如何更好地利用索引。

与其说它是子查询,不如说它是 IN 子句,尽管连接至少是 Oracle SQL 引擎的基础,并且运行得非常快。

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

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

通常,这是因为优化器无法指出子查询可以作为联接执行,在这种情况下,优化器为表中的每个记录执行子查询,而不是将子查询中的表与正在查询的表联接。一些更“企业”的数据库在这方面做得更好,但他们有时还是会错过。

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

但是,解释计划会告诉你一些肮脏的细节。

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

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

这样做:

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

我认为看到 MySQL 对这些查询的不同解释对每个人来说都是一次学习的经历。

在对数据集运行查询之前,查询将通过查询优化器进行组织,优化器试图以这样的方式组织查询,以便能够尽可能快地从结果集中删除尽可能多的元组(行)。通常当您使用子查询(特别是坏的子查询)时,元组无法从结果集中删除,直到外部查询开始运行。

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

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

下面是 子查询在 MySQL 6.0中进行计算

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

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

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

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