2012-10-25 198 views
0

我需要一個快速顯示用戶沒有上傳PDF的特定模塊(文章的子集)內的文章的查詢。我在下面使用的查詢大約需要37秒,因爲文章表中有300,000篇文章,模塊中有6,000篇文章。需要幫助加快MySQL查詢

SELECT * 
FROM article a 
INNER JOIN article_module_map amm ON amm.article=a.id 
WHERE amm.module = 2 AND 
    a.id NOT IN ( 
     SELECT afm.article 
     FROM article_file_map afm 
     INNER JOIN article_module_map amm ON amm.article = afm.article 
     WHERE afm.organization = 4 AND 
      amm.module = 2 
    ) 

我在上面的查詢做什麼首先截斷的文章,所選擇的模塊列表,然後再截斷該列表中沒有的子查詢中的文章。子查詢正在生成一個組織已經上傳PDF的文章列表。因此,最終結果是組織尚未上傳PDF的文章列表。

幫助將非常感激,在此先感謝!

編輯2012年10月25日

隨着@ fthiella的幫助,下面的查詢了驚人的1.02秒跑,低於37+秒!

SELECT a.* FROM (
    SELECT article.* FROM article 
    INNER JOIN article_module_map 
     ON article.id = article_module_map.article 
    WHERE article_module_map.module = 2 
) AS a 
LEFT JOIN article_file_map 
    ON a.id = article_file_map.article 
    AND article_file_map.organization=4 
WHERE article_file_map.id IS NULL 
+0

而不是顯示在同一頁中的所有文章我認爲一個好方法是實現一個分頁腳本..並顯示每個頁面20-30行..這將更快更快 –

+0

你嘗試看看解釋計劃爲了這?你的鑰匙是什麼?嘗試顛倒你的表中的順序也加入 –

+0

你在a.id,amm.article,afm.article的數據庫表上有索引嗎? – Adder

回答

1

我不知道我能正確理解表的邏輯和結構。這是我的查詢:

SELECT 
    article.id 
FROM 
    article 
    INNER JOIN 
    article_module_map 
    ON article.id = article_module_map.article 
    AND article_module_map.module=2 
    LEFT JOIN 
    article_file_map 
    ON article.id = article_file_map.article 
    AND article_file_map.organization=4 
WHERE 
    article_file_map.id IS NULL 

我提取了所有具有模塊2的文章。然後選擇那些組織4沒有提供文件的文章。

我使用了LEFT JOIN而不是子查詢。在某些情況下,這可能會更快。

編輯謝謝你的評論。我不確定它會跑得更快,但它讓我感到驚訝,它太慢了!無論如何,這是值得一試!現在

,出於好奇,我想嘗試LEFT /內的所有組合JOIN和子查詢,看看哪一個運行速度更快,例如:

SELECT * 
FROM 
    (SELECT * 
    FROM 
    article INNER JOIN article_module_map 
    ON article.id = article_module_map.article 
    WHERE 
    article_module_map.module=2) 
    LEFT JOIN 
etc. 

也許去除*,我想看看WHERE子句和ON子句的條件之間有什麼變化......無論如何,我認爲它沒有多大幫助,你現在應該專注於索引。

鍵/外鍵上的索引應該沒問題,但如果在和/或article_file_map.organization上添加索引,該怎麼辦?

+0

非常感謝您的努力!您的查詢現已發揮作用,因此您已經完成了一項出色的工作。不幸的是,它需要72秒的執行時間,而不是我的時間需要37秒。請注意,我用SELECT *替換了查詢中的SELECT,純粹是爲了比較執行時間。在我最後去的時候,我只會將它替換爲必填字段。 – skiindude22

+0

您編輯的查詢將執行時間從37秒延長到1秒......您是我的英雄!我在原始文章中包含了修改後的查詢,唯一的變化是我將SELECT語句中的字段指定爲我需要的字段。再次感謝你!! – skiindude22

+0

我很高興知道我編輯的查詢現在快得多:)謝謝!我有一些嫌疑犯,但這不容易解釋爲什麼它運行得更快......他們看起來非常相似!在這些情況下唯一要做的就是嘗試重寫查詢並嘗試使用不同的方法對錶進行分組! – fthiella

1

當優化查詢我用它來檢查以下幾點:

第一:我會盡量避免使用*在SELECT子句,而是命名你想要的diferent領域。這個速度瘋狂地增加了(我有一個用*花費了7秒,並且命名該域減少到了0.1s)。

第二:正如@Adder所說,將索引添加到您的表中。

第三:嘗試使用INNER JOIN而不是WHERE amm.module = 2 AND a.id NOT IN(...)。我認爲我讀過(我不記得它,所以要小心),通常MySQL優化INNER JOINS,並且作爲子查詢是一個過濾器,可能使用三個INNER JOINS和WHERE將更快地檢索。

+0

INNER JOIN只會返回兩個表中的文章嗎?我試圖獲得只包含article_file_map表中article_module_map表中的結果的結果,所以INNER JOIN會給我所有已經有PDF的文章,而不是那些沒有的文章。看起來可能的加入我想要的是一個左加入,但是,由於我需要檢查僅由某個組織上傳的PDF,因此這種方法對我也沒有幫助。我能夠捕獲所有條件的唯一方法就是使用子查詢。 – skiindude22

+0

嗨,我不知道你是否檢查過@fthiella提交的查詢,(我剛剛做過),但也許他的查詢比你的查詢快,並且正在返回所需的數據。無論如何,你是否嘗試了我寫給你的觀點?它在改善,還是一樣?我一直認爲你的主要問題是*和索引,然後是子查詢。 – Chococroc