optimiser la requête SQL
-
22-08-2019 - |
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
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.