2012-10-09 100 views
1

此查詢是接管一分鐘來完成:MySQL的JOIN時間減少

SELECT keyword, count(*) as 'Number of Occurences' 
    FROM movie_keyword 
    JOIN 
    keyword 
    ON keyword.`id` = movie_keyword.`keyword_id` 
    GROUP BY keyword 
    ORDER BY count(*) DESC 
    LIMIT 5 

每個關鍵字具有與它相關聯的ID(keyword_id列)。該ID用於從關鍵字表中查找實際的關鍵字。

movie_keyword有280萬行

關鍵字已經127000

但是隻返回最常用的keyword_id的僅需1秒鐘:

SELECT keyword_id, count(*) 
    FROM movie_keyword 
    GROUP BY keyword_id 
    ORDER BY count(*) DESC 
    LIMIT 5 

是否有這樣做的更有效的方法?

輸出與講解:

1 SIMPLE keyword ALL PRIMARY NULL NULL NULL 125405 Using temporary; Using filesort 
1 SIMPLE movie_keyword ref idx_keywordid idx_keywordid 4 imdb.keyword.id 28 Using index 

結構:

CREATE TABLE `movie_keyword` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `movie_id` int(11) NOT NULL, 
    `keyword_id` int(11) NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `idx_mid` (`movie_id`), 
    KEY `idx_keywordid` (`keyword_id`), 
    KEY `keyword_ix` (`keyword_id`), 
    CONSTRAINT `movie_keyword_keyword_id_exists` FOREIGN KEY (`keyword_id`) REFERENCES `keyword` (`id`), 
    CONSTRAINT `movie_keyword_movie_id_exists` FOREIGN KEY (`movie_id`) REFERENCES `title` (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=4256379 DEFAULT CHARSET=latin1; 

CREATE TABLE `keyword` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `keyword` text NOT NULL, 
    `phonetic_code` varchar(5) DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `idx_keyword` (`keyword`(5)), 
    KEY `idx_pcode` (`phonetic_code`), 
    KEY `keyword_ix` (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=127044 DEFAULT CHARSET=latin1; 
+0

你可以在SELECT前面用關鍵字'EXPLAIN'發表原始查詢的結果嗎?並顯示錶中的索引也將有所幫助 –

+0

這個數據庫是使用IMDB python工具生成的(我沒有設計實現) – Patrick

+0

感謝您的解釋 - 很可能您需要添加索引來使其更快 - 解釋給出信息 –

回答

1

未經測試,但應該工作,如果你被允許在mysql中雖然使用限制在一個子查詢,但也有周圍的其他方式更快的是顯著在我看來,沒有十分的把握。

SELECT keyword, count(*) as 'Number of Occurences' 
    FROM movie_keyword 
    JOIN 
    keyword 
    ON keyword.`id` = movie_keyword.`keyword_id` 
    WHERE movie_keyword.keyword_id IN (
     SELECT keyword_id 
     FROM movie_keyword 
     GROUP BY keyword 
     ORDER BY count(*) DESC  
     LIMIT 5 
    ) 
    GROUP BY keyword 
    ORDER BY count(*) DESC; 

這應該是更快,因爲你不使用關鍵字加入所有的280萬個條目movie_keyword,只是那些實際匹配,我猜是顯著少。

編輯因爲MySQL不支持,你必須運行

SELECT keyword_id 
FROM movie_keyword 
GROUP BY keyword 
ORDER BY count(*) DESC  
LIMIT 5; 

第一子查詢中獲取和限後的結果運行第二個查詢

SELECT keyword, count(*) as 'Number of Occurences' 
    FROM movie_keyword 
    JOIN 
    keyword 
    ON keyword.`id` = movie_keyword.`keyword_id` 
    WHERE movie_keyword.keyword_id IN (RESULTS_FROM_FIRST_QUERY_SEPARATED_BY_COMMAS) 
    GROUP BY keyword 
    ORDER BY count(*) DESC; 

與適當的替代RESULTS_FROM_FIRST_QUERY_SEPARATED_BY_COMMAS價值編程從您使用的任何語言

+0

我在想同樣的,但得到這個錯誤:_這個版本的MySQL還不支持'限制和IN /所有/任何/某些子查詢'_我正在運行5.5.28 – Patrick

+0

您的更新後的工作!我用測試值替換了結果,大約3秒鐘。謝謝! – Patrick

+0

沒問題,很高興我可以幫忙,只要有可能使用更智能的數據庫,mysql的限制使我做同樣的事情,每次我問我的客戶是否可以使用postgresql而不是mysql。 – xception

0

查詢看起來不錯,但我覺得結構不,試圖給在列指數

keyword.id 

試,

CREATE INDEX keyword_ix ON keyword (id); 

ALTER TABLE keyword ADD INDEX keyword_ix (id); 

,如果你可以發表你的表的結構要好得多:keywordMovie_keyword。哪兩個是主表和參考表?

SELECT keyword, count(movie_keyword.id) as 'Number of Occurences' 
FROM movie_keyword 
    INNER JOIN keyword 
      ON keyword.`id` = movie_keyword.`keyword_id` 
GROUP BY keyword 
ORDER BY 'Number of Occurences' DESC 
LIMIT 5 
+0

對此並且查詢仍然花費了一分多鐘。 – Patrick

+0

@帕特里克你可以發表表格的架構(結構)嗎?它會幫助我們解決問題的解決方法:) –

+0

添加結構。 – Patrick

0

我知道這是很老的questi但是因爲我認爲xception在mysql中忘記了交付表,我想提出另一種解決方案。它只需要一個查詢,並省略了連接大數據。如果有人有這麼大的數據並且可以測試它(可能是問題創建者),請分享結果。

SELECT keyword.keyword, _temp.occurences 
FROM (
    SELECT keyword_id, COUNT(keyword_id) AS occurences 
    FROM movie_keyword 
    GROUP BY keyword_id 
    ORDER BY occurences DESC 
    LIMIT 5 
) AS _temp 
JOIN keyword ON _temp.keyword_id = keyword.id 
ORDER BY _temp.occurences DESC