Question

Que puis-je faire pour optimiser cette requête?

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

Était-ce utile?

La solution

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

Mais je vous suggère aussi d'essayer de « nettoyer » votre déclaration. (Je ne sais pas lequel est plus rapide -. Cela dépend de votre taille de table) Habituellement, je vais essayer de commencer par une déclaration propre et commencer à optimiser à partir de là. Mais en général, une déclaration propre, il est plus facile pour l'optimiseur de venir avec un bon plan d'exécution.

Alors, voici 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
  • un grand nombre de colonnes par groupe

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)

WHERE

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 le groupe par. La jointure externe est remplacé par le sous-sélection, donc il y a un compromis qui peut être mauvais pour la déclaration « plus propre ».

En fonction de la cardinalité entre ce point et myItems, vous pouvez faire la même chose ou vous auriez à coller avec la jointure externe (mais pas besoin de réintroduire le groupe par).

Hope this helps.

Autres conseils

Qu'est-ce que l'analyseur dit pour cette requête? Sans connaissances sur le nombre de lignes, il y a dans le tableau que vous ne pouvez pas dire une optimisation. Donc, exécutez l'analyseur et vous verrez quelles parties coûts quoi.

Quelques réflexions semi-aléatoires rapides:

Vos colonnes Itemid et userId indexés?

Qu'est-ce qui se passe si vous ajoutez « Explain » au début de la requête et l'exécuter? Est-il utiliser les index? Sont-ils sensibles?

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

Vous ne semblez pas avoir trop de domaines dans le groupe par liste, puisque l'un d'eux est itemID, je pense que vous pouvez utiliser un SELECT pour préformer le groupe interne et un SELECT externe pour retourner l'ensemble des champs souhaités.

Tu ne peux pas ajouter la clause where myTable.userIDFav = 3 ou myTable.userIDFav est nulle Où (item.deleted = 0) ?

Cordialement
Lieven

Regardez la façon dont votre requête est construite. Vous rejoignez beaucoup de choses, puis limiter la sortie à 20 lignes. Vous devriez avoir la jointure externe sur les articles et myitems, étant donné que vos conditions ne concernent que ces deux tableaux, limiter la sortie aux 20 premières lignes, puis rejoindre et d'agrégats. Vous effectuez beaucoup de travail qui va être mis au rebut.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top