2009-02-12 7 views
3

Que puis-je faire de plus pour optimiser cette requête?optimiser la requête SQL

SELECT * FROM 
    (SELECT `item`.itemID, COUNT(`votes`.itemID) AS `votes`, 
      `item`.title, `item`.itemTypeID, `item`. 
      submitDate, `item`.deleted, `item`.ItemCat, 
      `item`.counter, `item`.userID, `users`.name, 
      TIMESTAMPDIFF(minute,`submitDate`,NOW()) AS 'timeMin' , 
      `myItems`.userID as userIDFav, `myItems`.deleted as myDeleted 
     FROM (votes `votes` RIGHT OUTER JOIN item `item` 
        ON (`votes`.itemID = `item`.itemID)) 
      INNER JOIN 
       users `users` 
      ON (`users`.userID = `item`.userID) 
    LEFT OUTER JOIN 
       myItems `myItems` 
      ON (`myItems`.itemID = `item`.itemID) 
    WHERE (`item`.deleted = 0) 
    GROUP BY `item`.itemID, 
       `votes`.itemID, 
       `item`.title, 
       `item`.itemTypeID, 
       `item`.submitDate, 
       `item`.deleted, 
       `item`.ItemCat, 
       `item`.counter, 
       `item`.userID, 
       `users`.name, 
       `myItems`.deleted, 
       `myItems`.userID 
    ORDER BY `item`.itemID DESC) as myTable 
where myTable.userIDFav = 3 or myTable.userIDFav is null 
      limit 0, 20 

J'utilise MySQL

Merci

Répondre

5

Bien sûr, comme @theomega dit, regardez le plan d'exécution.

Mais je suggère aussi d'essayer de "nettoyer" votre déclaration. (Je ne sais pas lequel est le plus rapide - cela dépend de la taille de votre table.) Habituellement, j'essaie de commencer par une déclaration propre et de commencer à optimiser à partir de là. Mais généralement, une instruction propre permet à l'optimiseur de proposer un plan d'exécution plus simple.

Voici donc quelques observations au sujet de votre déclaration qui pourrait faire les choses lentement:

  • deux jointures externes (il est difficile pour le optimzer de comprendre un indice à utiliser)
  • un groupe par
  • beaucoup de colonnes à groupe par

pour autant que je comprends votre SQL, cette déclaration devrait faire plus de ce que le vôtre est en train de faire:

SELECT `item`.itemID, `item`.title, `item`.itemTypeID, `item`. 
     submitDate, `item`.deleted, `item`.ItemCat, 
     `item`.counter, `item`.userID, `users`.name, 
     TIMESTAMPDIFF(minute,`submitDate`,NOW()) AS 'timeMin' 
    FROM (item `item` INNER JOIN users `users` 
     ON (`users`.userID = `item`.userID) 

Bien sûr, cela manque les informations des tables vous extérieur jointes, je vous suggère d'essayer d'ajouter les colonnes requises par une sous-sélection:

SELECT `item`.itemID, 
     (SELECT count (itemID) 
     FROM votes v 
     WHERE v.itemID = 'item'.itemID) as 'votes', <etc.> 

De cette façon, vous pouvez vous débarrasser d'une jointure externe et du groupe par.La jointure externe est remplacée par la sous-sélection, il y a donc un compromis qui peut être mauvais pour l'instruction "nettoyeur". Selon la cardinalité entre item et myItems, vous pouvez faire la même chose ou vous devrez coller avec la jointure externe (mais pas besoin de réintroduire le groupe).

Espérons que cela aide.

9

Qu'est-ce que l'analyseur dit pour cette requête? Sans connaître le nombre de lignes présentes dans le tableau, vous ne pouvez pas dire d'optimisation. Alors lancez l'analyseur et vous verrez quelles pièces coûtent quoi.

1

Quelques réflexions semi-aléatoires rapides:

sont vos colonnes itemID et userId indexé? Que se passe-t-il si vous ajoutez "EXPLAIN" au début de la requête et que vous l'exécutez? Utilise-t-il des index? Sont-ils sensibles?

Avez-vous besoin d'exécuter toute la requête interne et de filtrer dessus, ou pourriez-vous déplacer la partie where myTable.userIDFav = 3 or myTable.userIDFav is null dans la requête interne?

0

Vous semblez avoir trop de champs dans la liste Group By, puisque l'un d'eux est itemID, je suppose que vous pourriez utiliser un SELECT interne pour préformer le groupement et un SELECT externe pour retourner l'ensemble des champs désirés.

0

Pouvez-vous pas ajouter la clause where myTable.userIDFav = 3 ou myTable.userIDFav est nulle à OU (item .deleted = 0)?

Cordialement
Lieven

0

Regardez comment votre requête est construite. Vous joignez beaucoup de choses, puis limitez la sortie à 20 lignes. Vous devriez avoir la jointure externe sur les éléments et myitems, puisque vos conditions s'appliquent uniquement à ces deux tables, limitent la sortie aux 20 premières lignes, puis rejoignent et agrègent. Ici vous effectuez beaucoup de travail qui va être mis au rebut.