2009-11-19 63 views
6

我有这样的查询:我可以强制MySQL首先执行子查询吗?

SELECT `table_1`.* from `table_1` 
    INNER JOIN `table_2` [...] 
    INNER JOIN `table_3` [...] 
WHERE `table_1`.`id` IN(
    SELECT `id` FROM [...] 
) 
AND [more conditions] 

当我使用EXPLAIN,有“依赖SUBQUERY”末,但我要首先执行该子查询,之前的其他条件。

可以吗?

回答

2

您可以先将子查询的结果选择到临时表中,然后在主查询中加入它。

2

最好的方法是将table1的WHERE条件放入FROM子句中的子查询中。 EG:

SELECT `table_1`.* 
FROM (
     SELECT * FROM `table_1` WHERE `table_1`.`id` IN (...) 
    ) 
    INNER JOIN `table_2` [...] 
    INNER JOIN `table_3` [...] 
WHERE [more conditions] 
-1

不幸的是,不,你不能。子查询实际上为外部查询中的每一行运行一次。

我实际上建议您将其转换为另一个连接,并使用table_1.id作为另一个表的关键字。

13
SELECT `table_1`.* 
FROM `table_1` 
INNER JOIN 
     `table_2` [...] 
INNER JOIN 
     `table_3` [...] 
WHERE `table_1`.`id` IN 
     (
     SELECT `id` 
     FROM [...] 
     ) 
     AND [more conditions] 

如果内表正确编制索引,那么这里的子查询根本不是“严格意义上的”执行“。

由于子查询是IN表达式的一部分,因此将条件推入子查询中并将其转换为EXISTS

事实上,这种子查询每一步的评估:

EXISTS 
(
SELECT NULL 
FROM [...] 
WHERE id = table1.id 
) 

实际上,你可以看到它在由EXPLAIN EXTENDED提供的详细描述。

这就是为什么它被称为DEPENDENT SUBQUERY:每次评估的结果取决于table1.id的值。子查询本身不相关,它是相关的优化版本。

MySQL总是在更简单的过滤器之后评估EXISTS子句(因为它们更容易评估,并且有可能根本不评估子查询)。

如果你想在子查询一次全部进行评估,重写查询,因为这:

SELECT table_1.* 
FROM (
     SELECT DISTINCT id 
     FROM [...] 
     ) q 
JOIN table_1 
ON  table_1.id = q.id 
JOIN table_2 
ON  [...] 
JOIN table_3 
ON  [...] 
WHERE [more conditions] 

这迫使子查询被领先的加盟,这是更有效的,如果比较的子查询小到table_1,如果子查询比table_1大,则效率较低。

如果在子查询中使用的[...].id上有索引,则子查询将使用INDEX FOR GROUP-BY执行。

+0

按下子查询的问题是,如果子查询依赖于外部查询的常量部分,则这是不可能的(请参阅https://stackoverflow.com/questions/44859809/how-to-optimize-dependent-subquery -with-constant-expression) – andig 2017-07-01 10:43:06

3

这是一个已知的错误在MySQL:http://bugs.mysql.com/bug.php?id=25926

一个有用的解决方法是将子查询下推到另一个select * from (subquery) as dt类型子查询。

+0

你提到的bug只影响'GROUP BY/DISTINCT'子查询。子查询中带有“DISTINCT”子句的“IN”谓词等同于“JOIN”。 – Quassnoi 2009-11-19 22:17:27

+1

不,这个问题也会出现在不涉及“GROUP BY”或“DISTINCT”的查询中。反驳这很简单:按照我的建议将子查询推向另一个级别,并查看依赖子查询是否更改为DERIVED表。 (你怎么知道这个查询没有GROUP BY?原始海报没有提供真正的查询。) – longneck 2009-11-20 02:41:29

+0

这个解决方法对我有用:它花了一个查询,查看时间从32分钟缩短到0.452秒。谢谢! – Deebster 2010-09-29 15:21:26

相关问题