2012-10-09 6 views
1

Cette requête prend plus d'une minute pour terminer:MySQL REJOIGNEZ réduction du temps

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 

Chaque mot-clé a un ID associé (colonne keyword_id). Et cet ID est utilisé pour rechercher le mot clé réel à partir du tableau de mots clés.

movie_keyword a 2,8 millions de lignes

mot-clé a 127000

Cependant, pour revenir prend juste est le plus utilisé keyword_id seulement 1 seconde:

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

est-il un moyen plus efficace de le faire?

sortie avec EXPLIQUEZ:

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 

Structure:

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

Pouvez-vous poster les résultats de votre requête d'origine avec le mot-clé 'EXPLAIN' devant le SELECT. Et montrant les index de la table aiderait également –

+0

Cette DB a été générée en utilisant un outil python IMDB (je n'avais aucune implémentation de conception) – Patrick

+0

Merci pour l'EXPLAIN - il est probable que vous avez besoin d'ajouter des index pour le rendre plus rapide - l'explication donne l'info –

Répondre

1

Untested mais devrait fonctionner et être beaucoup plus rapide à mon avis, pas très sûr si vous êtes autorisé à utiliser la limite dans une sous-requête dans une base MySQL bien, mais il y a d'autres façons de contourner cela.

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; 

Cela devrait être plus rapide parce que vous ne joignez pas tous les 2,8 millions d'entrées en movie_keyword avec mot-clé, à seulement ceux qui correspondent en fait, que je devine sont beaucoup moins.

EDIT depuis MySQL ne supporte pas la limite dans un sous-requête vous devez exécuter

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

premier et après les résultats vont aller chercher la deuxième requête

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 avec le remplacer bon valeurs par programme de la langue que vous utilisez

+0

Je pensais la même chose, mais obtenir cette erreur: _Cette version de MySQL ne supporte pas encore 'LIMIT & IN/ALL/ANY/QUELQUES sous-requêtes'_ Je cours 5.5.28 – Patrick

+0

Votre poste mis à jour a fonctionné! J'ai remplacé les résultats par des valeurs de test et c'était ~ 3 secondes. Je vous remercie! – Patrick

+0

Pas de problème, contente que je puisse aider, autant que possible utiliser des bases de données plus intelligentes, les limitations de mysql m'ont incité à faire de même, chaque fois que je demande à mes clients si je peux utiliser postgresql au lieu de mysql. – xception

0

La requête semble bien, mais je pense que la structure n'est pas, essayez de donner l'index sur les colonnes

keyword.id 

essayer ,

CREATE INDEX keyword_ix ON keyword (id); 

ou

ALTER TABLE keyword ADD INDEX keyword_ix (id); 

beaucoup mieux si vous pouvez afficher les structures de vos tables: keyword et Movie_keyword. Lequel des deux est la table principale et la table de référence?

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

Ran ce et la requête a pris plus d'une minute. – Patrick

+0

@Patrick pouvez-vous poster le schéma (structure) des tables s'il vous plaît? cela nous aidera à obtenir la solution de contournement de votre problème :) –

+0

Ajout de la structure. – Patrick

0

Je sais que c'est assez vieux questi sur, mais parce que je pense que xception a oublié les tables de livraison dans mysql, je veux suggérer une autre solution. Il ne nécessite qu'une seule requête et omet de joindre des big data. Si quelqu'un a de telles données et peut les tester (peut-être questionner le créateur), merci de partager les résultats.

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