2013-03-20 121 views
1

(可能是重複的,但我只能找到與JOIN [3]的問題和解決方案,這就是不是一個選項哪個子查詢更快?

我有兩個表。非常薄(很少列)和非常長(很多行)。一個是數據表(articles),另一個是ACL表(acl)。

我想只顯示通過acl.some_id訪問的文章。哪個子查詢更快?

[1] 
SELECT a.title 
FROM articles a 
WHERE 0 < (
    SELECT COUNT(1) 
    FROM acl 
    WHERE article_id = a.id AND some_id IN (1, 2, 3) 
) 

[2] 
SELECT a.title 
FROM articles a 
WHERE a.id IN (
    SELECT article_id 
    FROM acl WHERE some_id IN (1, 2, 3) 
) 

我心中想說的第二個,因爲子查詢可重複使用的所有潛在的匹配行,因此將只執行一次(雖然結果集將是非常大的),而第一個子查詢將不得不檢查每一個可能匹配的行。

還有第三種方法,但這是不是一個選項,因爲它會重複行(和GROUP BY不是解決方案,因爲我需要COUNT以後的其他東西(和DISTINCT永遠不是解決方案!)):

[3] 
SELECT a.title 
FROM articles a 
JOIN acl 
    ON acl.article_id = a.id 
WHERE acl.some_id IN (1, 2, 3) 

由於article_id的X存在N次acl,它將返回該行0 - N次,而不是0 - 1

還有第四個方法:EXISTS。感謝ypercube。

相關:

+5

你寫的代碼... **嘗試它,並找出來!** – 2013-03-20 22:20:07

+0

嘗試一次或15次並不意味着什麼。我想要爲什麼。而且這些表格還不長=),所以執行時間將非常非常短。 – Rudie 2013-03-20 22:21:32

+3

mysql擁有你需要自己回答這個問題的所有工具。查看每個查詢的執行計劃。查看執行時間。你可以這樣做。 – 2013-03-20 22:24:11

回答

5

我要說[2],太,但MySQL有優化IN子查詢,至少高達5.5的一些盲點。 (新發布的)5.6版本中查詢優化器有幾項改進。您可以在MySQL文檔中閱讀關於(semijoins和IN子查詢):MySQL 5.6: Optimizing Subqueries with Semi-Join Transformations

MariaDB(版本5.3和5.5)中的優化器也有一些改進,其中一些與這類查詢有關。您可以在他們的文檔中閱讀:MariaDB 5.3: Semi-join subquery optimizations

您也可以嘗試EXISTS版本,特別是如果你使用的是5.5或以上版本:

-- [4] 
SELECT id 
FROM articles AS a 
WHERE EXISTS (
    SELECT * 
    FROM acl 
    WHERE acl.some_id IN (1, 2, 3) 
    AND acl.article_id = a.id 
) ; 

我覺得(article_id, some_id)指數將在這裏有用的 - 或者相反的一個,它不傷害嘗試兩個。


如果從acl (article_id) REFERENCES article (id)外鍵,你可以信任,而你只需要在文章的ID,你也可以只從一個表中的數據:

SELECT DISTINCT article_id 
FROM acl 
WHERE acl.some_id IN (1, 2, 3) ; 

當然你應該測試你服務器中的幾個版本,你有(或計劃使用)的MySQL版本,數據分佈,當然還有足夠大的表格。用幾百行進行測試不會告訴你很多。

+0

啊是的EXISTS,這也是一個選項。聽起來就像它是爲了做到這一點。 (我有那些索引btw。) – Rudie 2013-03-20 22:29:02

+0

存在,我認爲。顯然比IN + COUNT快得多:http://www.jortk.nl/2008/07/exists-much-faster-then-in-in-mysql/(儘管這很舊)。可能是因爲EXISTS在找到1條記錄後停止/返回。 – Rudie 2013-03-20 22:31:58

+0

最後一個查詢(僅返回文章ID)是不夠的,因爲我想要的不僅僅是文章ID。抱歉。不夠明顯。 – Rudie 2013-03-20 22:36:44