2012-10-09 98 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