2009-11-19 62 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

相關問題