2011-09-26 8 views
0

J'ai la requête suivante:Comment rendre cette requête SQL plus rapide?

SELECT DISTINCT `movies_manager_movie`.`id`, 
       `movies_manager_movie`.`title`, 
       `movies_manager_movie`.`original_title`, 
       `movies_manager_movie`.`synopsis`, 
       `movies_manager_movie`.`keywords`, 
       `movies_manager_movie`.`release_date`, 
       `movies_manager_movie`.`rating`, 
       `movies_manager_movie`.`poster_web_url`, 
       `movies_manager_movie`.`has_poster`, 
       `movies_manager_movie`.`number`, 
       `movies_manager_movie`.`has_sources`, 
       `movies_manager_movie`.`season_id`, 
       `movies_manager_movie`.`created`, 
       `movies_manager_movie`.`updated`, 
       `movies_manager_moviecache`.`activity_name` 

FROM `movies_manager_movie` 

LEFT OUTER JOIN `movies_manager_moviecache` ON (`movies_manager_movie`.`id` = `movies_manager_moviecache`.`movie_id`) 

WHERE (`movies_manager_movie`.`has_sources` = 1 
     AND (`movies_manager_moviecache`.`team_member_id` IN (

      SELECT U0.`id` FROM `movies_manager_movieteammember` U0 
      INNER JOIN `movies_manager_movieteammemberactivity` U1 ON (U0.`id` = U1.`team_member_id`) 
      WHERE U1.`movie_id` = 3588) 
       AND `movies_manager_movie`.`number` IS NULL 
     ) 

    AND NOT (`movies_manager_movie`.`id` = 3588)) 
    ORDER BY `movies_manager_moviecache`.`activity_name` DESC LIMIT 3; 

Cette requête peut prendre jusqu'à 3 secondes et je suis surprise très depuis que je suis index partout et pas plus de 35 lignes dans chacune de mes tables MyISAM, en utilisant la dernière Version MySQL

J'ai mis en cache tout ce que je pouvais mais j'ai au moins besoin d'exécuter celui-ci 20000 fois par jour, ce qui représente environ 16 heures d'attente pour le chargement. Et je suis à peu près sûr qu'aucun de mes utilisateurs (ni Google Bot) n'apprécie un temps d'attente de 4 secondes pour chaque chargement de page.

Que puis-je faire pour le rendre plus rapide?

Je pensais à la duplication de champ de movie à moviecache puisque le but du cache de film est de dénormaliser en compliant déjà.

J'ai essayé d'associer la sous-requête à une liste d'ID mais cela a étonnamment doublé le temps de la requête.

Tables:

+----------------+--------------+------+-----+---------+----------------+ 
| Field   | Type   | Null | Key | Default | Extra   | 
+----------------+--------------+------+-----+---------+----------------+ 
| id    | int(11)  | NO | PRI | NULL | auto_increment | 
| title   | varchar(120) | NO | UNI | NULL |    | 
| original_title | varchar(120) | YES |  | NULL |    | 
| synopsis  | longtext  | YES |  | NULL |    | 
| keywords  | varchar(120) | YES |  | NULL |    | 
| release_date | date   | YES |  | NULL |    | 
| rating   | int(11)  | NO |  | NULL |    | 
| poster_web_url | varchar(255) | YES |  | NULL |    | 
| has_poster  | tinyint(1) | NO |  | NULL |    | 
| number   | int(11)  | YES |  | NULL |    | 
| season_id  | int(11)  | YES | MUL | NULL |    | 
| created  | datetime  | NO |  | NULL |    | 
| updated  | datetime  | NO |  | NULL |    | 
| has_sources | tinyint(1) | NO |  | NULL |    | 
+----------------+--------------+------+-----+---------+----------------+ 
+---------------------+--------------+------+-----+---------+----------------+ 
| Field    | Type   | Null | Key | Default | Extra   | 
+---------------------+--------------+------+-----+---------+----------------+ 
| id     | int(11)  | NO | PRI | NULL | auto_increment | 
| name    | varchar(120) | NO | UNI | NULL |    | 
| biography   | longtext  | YES |  | NULL |    | 
| birth_date   | date   | YES |  | NULL |    | 
| picture_web_url  | varchar(255) | YES |  | NULL |    | 
| allocine_link  | varchar(255) | YES |  | NULL |    | 
| created    | datetime  | NO |  | NULL |    | 
| updated    | datetime  | NO |  | NULL |    | 
| has_picture   | tinyint(1) | NO |  | NULL |    | 
| biography_linkyfied | longtext  | YES |  | NULL |    | 
+---------------------+--------------+------+-----+---------+----------------+ 

+----------------+--------------+------+-----+---------+----------------+ 
| Field   | Type   | Null | Key | Default | Extra   | 
+----------------+--------------+------+-----+---------+----------------+ 
| id    | int(11)  | NO | PRI | NULL | auto_increment | 
| movie_id  | int(11)  | NO | MUL | NULL |    | 
| tag_slug  | varchar(100) | YES | MUL | NULL |    | 
| team_member_id | int(11)  | YES | MUL | NULL |    | 
| cast_rank  | int(11)  | YES |  | NULL |    | 
| activity_name | varchar(30) | YES | MUL | NULL |    | 
+----------------+--------------+------+-----+---------+----------------+ 

Mysql me dit qu'il est une requête lente:

# Query_time: 3 Lock_time: 0 Rows_sent: 9 Rows_examined: 454128 
+4

Remplacer IN avec JOIN. Recherche - il y a beaucoup d'exemples au SO –

+1

Avez-vous vraiment besoin du distinct aussi bien? – Ben

+0

Je ne sais pas comment je peux faire une suggestion de Darhazer. @Ben: Je n'ai besoin d'afficher qu'un seul résultat pour chaque film de la page. Si je peux le faire d'une autre manière, je suis d'accord pour supprimer distinct. –

Répondre

1

Déplacer movies_manager_movieteammemberactivity et movies_manager_movieteammember à votre déclaration principale join (de sorte que vous faites une jointure externe gauche entre movies_manager_movie et le produit de jointure interne des 3 autres tables). Cela devrait considérablement accélérer votre requête.

+0

Ok. Mais comment mettre l'instruction 'IN' dans la jointure principale? –

1

Essayez ceci:

SELECT `movies_manager_movie`.`id`, 
    `movies_manager_movie`.`title`, 
    `movies_manager_movie`.`original_title`, 
    `movies_manager_movie`.`synopsis`, 
    `movies_manager_movie`.`keywords`, 
    `movies_manager_movie`.`release_date`, 
    `movies_manager_movie`.`rating`, 
    `movies_manager_movie`.`poster_web_url`, 
    `movies_manager_movie`.`has_poster`, 
    `movies_manager_movie`.`number`, 
    `movies_manager_movie`.`has_sources`, 
    `movies_manager_movie`.`season_id`, 
    `movies_manager_movie`.`created`, 
    `movies_manager_movie`.`updated`, 
    (
     SELECT `movies_manager_moviecache`.`activity_name` 
     FROM `movies_manager_moviecache` 
     WHERE (`movies_manager_movie`.`id` = `movies_manager_moviecache`.`movie_id` 
      AND (`movies_manager_moviecache`.`team_member_id` IN (
       SELECT U0.`id` FROM `movies_manager_movieteammember` U0 
        INNER JOIN `movies_manager_movieteammemberactivity` U1 ON (U0.`id` = U1.`team_member_id`) 
       WHERE U1.`movie_id` = 3588) 
      AND `movies_manager_movie`.`number` IS NULL 
     )) LIMIT 1) AS `activity_name` 
FROM `movies_manager_movie`  
WHERE (`movies_manager_movie`.`has_sources` = 1 
    AND NOT (`movies_manager_movie`.`id` = 3588)) 
ORDER BY `activity_name` DESC 
LIMIT 3; 

Laissez-moi savoir comment qui effectue

Questions connexes