2013-10-02 26 views
1
SELECT * FROM foo f 
INNER JOIN (
    SELECT bar_id, MAX(revision_id) FROM bar b 
    GROUP BY bar_id 
) t ON t.bar_id = f.bar_id 

好吧,聽到這樣的問題:可以說這些表中有數百萬條記錄,我希望查詢儘可能高效。最有效的子查詢過濾器位置(GROUP BY)加入

MySQL是否將拉條表的所有記錄,然後在連接級別的ON語句而不是在子查詢中過濾它們?或者有沒有一種方法可以在JOIN過濾器之前用SQL本身過濾子查詢中的項目?

它似乎查詢所有的記錄來過濾它們將是低效的,我還沒有想到一種方法來解決這個問題。

我都試過,但子查詢中無法看到foo表:

SELECT * FROM foo f 
INNER JOIN (
    SELECT bar_id, MAX(revision_id) FROM bar b 
    WHERE b.bar_id = f.bar_id 
    GROUP BY bar_id 
) t ON t.bar_id = f.bar_id 

有沒有辦法向下傳遞ID的子查詢,我只是喜歡做的事情的最佳方式,而且我我確定有辦法做到這一點。

感謝您的回覆。

+0

您可以添加索引來提高性能 –

+0

您還可以發佈解釋並顯示創建表和記錄數量嗎? –

回答

0

是MySQL的打算把所有的記錄欄表,然後在加入的水平,而不是子查詢中他們篩選的ON聲明?

很可能,它會在完成連接之前完成子查詢。如果您想確切知道,請看EXPLAIN顯示的執行計劃。

有一個特殊的情況下這種做法甚至可能是有益的:如果bar大,但bar_id只需要幾個值,如果從foo參考多行這些相同的幾個bar_id值,然後選擇最大改版每個ID最多在將它們加入foo行之前,可能會很好。

或者有沒有一種方法可以在JOIN過濾器之前用SQL自己過濾子查詢中的項目?

你可以完全避免的子查詢:

SELECT f.*, MAX(b.revison_id) 
FROM foo f INNER JOIN bar b ON b.bar_id = f.bar_id 
GROUP BY f.foo_id 

我假設在foo的每一行都可以通過其foo_id被唯一標識;你可能需要在那裏使用多個列,或者引入新的密鑰。因此,foo中每個行的結果都會包含一行,但只有在bar中至少有一個匹配行時也是如此。 bar中的所有行將在MAX調用中彙總,因此您可以從這些行中獲得最大revision_id

我都試過,但子查詢中無法看到foo表:[...]

一件好事,這並不工作。關閉工作將是一些依賴查詢,這將不得不重複執行,每一行foo行一次。這是一個性能殺手。如果有疑問,請嘗試使用您的真實數據,並簡單比較足夠多的執行次數的執行時間。

結論:儘量避免使用subquerys,儘量避免使用依賴子查詢。

+0

你確定上面的代碼會運行嗎? SQL標準認爲每個列不是聚合函數的一部分應該包含在GROUP BY子句中,並且來自'foo'表格的列不是... –

+0

MySQL對該規範的那部分不太嚴格,並且允許未分組的列通過選擇一個任意一個。但是你的問題提出了一個很好的觀點:我隱含地認爲,條中的每一行在foo中最多隻匹配一行,這可能是一個無效的假設。因此,您寧願使用某些唯一標識foo行的密鑰進行分組。你有'foo_id'嗎?我會在我的答案中使用它。 – MvG