2012-04-24 41 views
0

有什麼辦法如何優化一個查詢:能不能用數據[MySQL的]的大量更快執行

EXPLAIN EXTENDED SELECT keyword_id, ck.keyword, COUNT(article_id) AS cnt 
FROM career_article_keyword 
LEFT JOIN career_keywords ck 
USING (keyword_id) 
WHERE keyword_id 
IN (

SELECT keyword_id 
FROM career_article_keyword 
LEFT JOIN career_keywords ck 
USING (keyword_id) 
WHERE article_id 
IN (

SELECT article_id 
FROM career_article_keyword 
WHERE keyword_id =9 
) 
AND keyword_id <>9 
) 
GROUP BY keyword_id 
ORDER BY cnt DESC 

主要任務在這裏,如果我有特別的keyword_id(CURRENT_KID)我需要找到所有這是曾經與CURRENT_KID一起屬於任何物品,並且排序關鍵字結果基於使用量的這些關鍵字

表定義爲:的「解釋」

mysql> show create table career_article_keyword; 
+------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 
| Table     | Create Table                                                                                    | 
+------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 
| career_article_keyword | CREATE TABLE `career_article_keyword` (
    `article_id` int(11) unsigned NOT NULL, 
    `keyword_id` int(11) NOT NULL, 
    UNIQUE KEY `article_id` (`article_id`,`keyword_id`), 
    CONSTRAINT `career_article_keyword_ibfk_1` FOREIGN KEY (`article_id`) REFERENCES `career` (`menu_id`) ON DELETE CASCADE ON UPDATE CASCADE 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 | 
+------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 
1 row in set (0.00 sec) 

mysql> show create table career_keywords; 
+-----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 
| Table   | Create Table                                                   | 
+-----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 
| career_keywords | CREATE TABLE `career_keywords` (
    `keyword_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT, 
    `keyword` varchar(250) NOT NULL, 
    PRIMARY KEY (`keyword_id`) 
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8 | 
+-----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 
1 row in set (0.00 sec) 

輸出嚇死我了

http://o7.no/J6ThIs

大數據這個查詢可以殺死一切:)我可以使其更快不知何故?

謝謝。

回答

2

看看你的EXPLAIN輸出,我擔心你使用子查詢會導致索引使用次優。我感覺(沒有任何理由 - 對此我可能是錯誤的),重寫使用JOIN可能會導致更優化的查詢。

要做到這一點,我們需要了解查詢的目的是什麼。如果你的問題已經闡明瞭它的話,這將會有所幫助,但是在經過一番討論之後,我決定你的查詢試圖獲取列表中包含某個給定關鍵字的任何文章中出現的所有其他關鍵字的列表,以及所有其他關鍵字的計數那些關鍵詞出現的文章

現在,讓我們重建階段查詢:

  1. 取 「包含某些特定關鍵字任何物品」(不擔心重複):

    SELECT ca2.article_id 
    FROM 
         career_article_keyword AS ca2 
    WHERE 
         ca2.keyword_id = 9; 
    
  2. 取「所有出現在[上述]中的其他關鍵字

    SELECT ca1.keyword_id 
    FROM 
         career_article_keyword AS ca1 
        JOIN career_article_keyword AS ca2 ON (ca2.article_id = ca1.article_id) 
    WHERE 
         ca1.keyword_id <> 9 
        AND ca2.keyword_id = 9 
    GROUP BY ca1.keyword_id; 
    
  3. 取「[以上],在其中這些關鍵字出現所有文章的計數一起」

    SELECT ca1.keyword_id, COUNT(DISTINCT ca0.article_id) AS cnt 
    FROM 
         career_article_keyword AS ca0 
        JOIN career_article_keyword AS ca1 USING (keyword_id) 
        JOIN career_article_keyword AS ca2 ON (ca2.article_id = ca1.article_id) 
    WHERE 
         ca1.keyword_id <> 9 
        AND ca2.keyword_id = 9 
    GROUP BY ca1.keyword_id 
    ORDER BY cnt DESC; 
    
  4. 最後,我們要添加到輸出匹配關鍵字本身從career_keyword表:

    SELECT ck.keyword_id, ck.keyword, COUNT(DISTINCT ca0.article_id) AS cnt 
    FROM 
         career_keywords  AS ck 
        JOIN career_article_keyword AS ca0 USING (keyword_id) 
        JOIN career_article_keyword AS ca1 USING (keyword_id) 
        JOIN career_article_keyword AS ca2 ON (ca2.article_id = ca1.article_id) 
    WHERE 
         ca1.keyword_id <> 9 
        AND ca2.keyword_id = 9 
    GROUP BY ck.keyword_id -- equal to ca1.keyword_id due to join conditions 
    ORDER BY cnt DESC; 
    

有一件事是立即清除的是,你的原始查詢引用career_keywords兩次,而這個重寫的查詢只引用該表一次;這本身可能解釋性能差異 - 嘗試刪除對它的第二個引用(即它出現在第一個子查詢中的位置),因爲它在那裏完全是多餘的。

回首這個查詢,我們可以看到,連接被安排在隨後的列進行:

  • career_keywords.keyword_idck JOIN ca0

    此表定義PRIMARY KEY (`keyword_id`),所以有一個很好的指標可用於此連接。

  • career_article_keyword.article_idca1 JOIN ca2

    此表定義UNIQUE KEY `article_id` (`article_id`,`keyword_id`),並且由於article_id是在該索引中的最左邊的列中,是可用於該連接的良好指標。

  • career_article_keyword.keyword_idck JOIN ca0ca0 JOIN ca1

    沒有可用於索引這個連接:此表中定義的唯一索引有另一列,article_idkeyword_id左 - 因此MySQL無法找到keyword_id條目在索引中沒有先知道article_id。我建議你創建一個新的索引,其最左邊的列爲keyword_id

    (需有此指數同樣可以被直接看着你的原始查詢,你的兩個最外面的查詢執行連接該列確定。)

+0

不幸查詢resturn錯誤的數據:(您可以在這裏看看我的和你的版本http://o7.no/IFXd5m – user1016265 2012-04-25 07:16:58

+0

@ user1016265:上面的修改版本現在應該是正確的了,你必須將自己的'career_article_keyword'表格加入自己三次(找到包含關鍵字,在這些文章中查找所有其他關鍵字,計算包含這些關鍵字的所有文章),所以如果該表變大,這肯定是一個問題;您是否嘗試過對您的查詢進行基準比較, ne(創建新的索引後,我建議)? – eggyal 2012-04-25 08:46:36

+0

非常少量的數據感謝您的查詢需要0.0010秒。我的是:0.0028。通過添加SQL_NO_CACHE語句來調整兩個查詢。首先執行你的和二級礦井。當我添加建議索引時,更有趣的東西變成了。結果是:你的 - 0.0006,我的 - 0.0009。現在我需要了解這個與包括同一張桌子的三重魔法:)謝謝。 – user1016265 2012-04-25 13:32:06