子查询与连接

时间:2008-09-26 18:58:54

标签: sql mysql performance database-design join

我重构了一个从另一家公司继承的应用程序的缓慢部分,以使用内连接而不是像

这样的子查询
where id in (select id from ... )

重构的查询运行速度提高了大约100倍。(~50秒~~ 0.3)我预计会有所改善,但有人可以解释为什么它如此激烈吗? where子句中使用的列都已编入索引。 SQL是否每行执行一次where子句中的查询?

更新 - 解释结果:

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

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

14 个答案:

答案 0 :(得分:155)

“相关子查询”(即,where条件依赖于从包含查询的行获得的值)将对每行执行一次。非相关子查询(where条件独立于包含查询的子查询)将在开头执行一次。 SQL引擎自动进行区分。

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

答案 1 :(得分:36)

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

答案 2 :(得分:16)

以下是subqueries are evaluated in MySQL 6.0

的示例

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

答案 3 :(得分:7)

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

答案 4 :(得分:6)

在针对数据集运行查询之前,优化器会尝试以这样的方式组织查询,即可以尽可能快地从结果集中删除任意数量的元组(行)。通常当您使用子查询(尤其是坏查询)时,在外部查询开始运行之前,无法从结果集中删除元组。

没有看到查询很难说原始内容有多糟糕,但我的猜测是优化器无法做得更好。运行'explain'将显示用于检索数据的优化器方法。

答案 5 :(得分:4)

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

答案 6 :(得分:4)

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

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

这样做:

对每个查询(JOIN'ed,然后是Subqueried)运行一个EXPLAIN,并在此处发布结果。

我认为看到MySQL对这些查询的解释存在差异,这将是每个人的学习经历。

答案 7 :(得分:4)

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

答案 8 :(得分:3)

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

加入的位置通常可以使用相同的执行计划实施,因此通常为零从他们之间的变化加速。

答案 9 :(得分:3)

优化器并没有做得很好。通常它们可以在没有任何差异的情况下进行转换,优化器也可以这样做。

答案 10 :(得分:3)

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

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

答案 11 :(得分:2)

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

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

答案 12 :(得分:2)

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

答案 13 :(得分:2)

取自参考手册(14.2.10.11 Rewriting Subqueries as Joins):

  

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

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