2013-07-04 6 views
0
SELECT links.* 
FROM links 
INNER JOIN (
    SELECT keywords_links.link_id 
    FROM keywords_links 
    INNER JOIN keywords ON keywords_links.keyword_id = keywords.id 
    WHERE keywords.keyword 
    IN ("facebook", "google", "apple") 
    GROUP BY keywords_links.link_id 
) t 
ON links.id = t.link_id 

Ceci renvoie les liens correspondant à un ou plusieurs mots-clés. J'ai 3 tables: links, keywords, et keywords_links. Le keywords_links relie les mots-clés aux liens.La requête MySQL est lente

Comment rendre cette requête plus efficace? Je suis inexpérimenté avec MySQL, j'ai donc dû utiliser des commandes MySQL de base pour créer cette requête.

Tableaux (uniquement des informations pertinentes affichées):

Liens:

CREATE TABLE IF NOT EXISTS `links` (
    `id` int(11) NOT NULL auto_increment, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `url` (`url`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=337789 ; 

keywords_links:

CREATE TABLE IF NOT EXISTS `keywords_links` (
    `keyword_id` int(11) NOT NULL, 
    `link_id` int(11) NOT NULL 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

mots-clés:

CREATE TABLE IF NOT EXISTS `keywords` (
    `id` int(11) NOT NULL auto_increment, 
    `keyword` varchar(100) NOT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `sort` (`id`,`keyword`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=60363 ; 
+0

Pourquoi avez-vous besoin de 'GROUP BY' ici? – zerkms

+0

1. Afficher 'EXPLAIN' 2. Montrer' CREATE TABLE' pour chaque table. – zerkms

+0

Assurez-vous que vous avez des index sur toutes les colonnes utilisées dans les clauses 'ON' et' WHERE'. – Barmar

Répondre

0

la requête elle-même est ok. Le problème de performance est probablement qu'il doit faire une analyse de table complète de keywords_links pour faire correspondre les mots-clés et un balayage de table complet sur les mots-clés pour trouver les correspondances.

Essayez de changer les structures de table à:

CREATE TABLE IF NOT EXISTS `keywords` (
    `id` int(11) NOT NULL auto_increment, 
    `keyword` varchar(100) NOT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `sort` (`id`,`keyword`), 
    INDEX (keyword) 
) ; 

Cela permettra d'accélérer le match de mot-clé (vous pouvez aussi utiliser create index).

Ensuite, vous pouvez donc trouver les liens plus rapidement:

CREATE TABLE IF NOT EXISTS `keywords_links` (
    `keyword_id` int(11) NOT NULL, 
    `link_id` int(11) NOT NULL, 
    unique (keyword_id, link_id) 
); 

La combinaison de trouver les correspondances aux mots-clés à travers un index, puis de trouver les liens à travers un index devrait accélérer la requête.

+0

Dès qu'il est innodb, alors pour la table 'keyword' l'unique index' keyword' serait suffisant. Donc seulement 2 index au total: 'PK (id)' et 'UNIQUE KEY (mot-clé)' – zerkms

+0

@zerkms. . . Vous avez raison. Dans la question, l'instruction est 'tri unique (id, mot-clé)', ce qui est assez différent. –

0
SELECT DISTINCT 
    l.* 
FROM 
links l 
INNER JOIN keyworks_links kl ON kl.link_id = l.id 
INNER JOIN keywords ON kl.keyword_id = k.id 
WHERE 
    k.keyword IN ("facebook", "google", "apple") 
; 

EDIT Ajouté DISTINCT pour supprimer les doublons

+0

Qu'est-ce qui rendrait cette course plus rapide? –

+0

Parce que dans le format d'origine, il crée une table en ligne (la sous-sélection dans le), puis rejoint cette table en ligne avec la table des liens.La table inline n'utilisera pas d'index pour rejoindre, avec ceci, mysql utilisera des index (si nécessaire) – Aguardientico

+0

Juste une remarque: la requête de la question ne garantit aucun doublon 'link_id' dans la requête imbriquée, alors que la requête de cette réponse ne le fait pas 't – zerkms