Cette requête :
SELECT *
FROM listings
WHERE (publishedon BETWEEN 1441105258 AND 1443614458) AND
(published = 1) AND
(cat_id in (1,2,3,4,5)) AND
(source_id in (1,2,3,4,5));
Est difficile à optimiser avec seulement des index. Le meilleur index est celui qui commence par published puis a les autres colonnes - il n'est pas clair quel devrait être leur ordre. La raison en est que tous sauf published n'utilisent pas = .
Étant donné que votre problème de performances concerne un tri, cela suggère que de nombreuses lignes sont renvoyées. Typiquement, un index est utilisé pour satisfaire le WHERE clause avant que l'index puisse être utilisé pour le ORDER BY . Cela rend cela difficile à optimiser.
Suggestions . . . Aucun n'est aussi génial :
- Si vous avez l'intention d'accéder aux données par mois, vous pouvez envisager de partitionner les données par mois. Cela fera la requête sans le
ORDER BYplus rapide, mais n'aidera pas leORDER BY. - Essayez différents ordres de colonnes après
publisheddans l'indice. Vous pourriez trouver la ou les colonnes les plus sélectives. Mais, encore une fois, cela accélère la requête avant le tri. - Pensez aux façons dont vous pouvez structurer la requête pour avoir plus de conditions d'égalité dans
WHEREclause ou pour renvoyer un ensemble de données plus petit. - (Pas vraiment recommandé) Mettre un index sur
publishedet la colonne de commande. Utilisez ensuite une sous-requête pour récupérer les données. Mettez les conditions d'inégalité (INet ainsi de suite) dans la requête externe. La sous-requête utilisera l'index pour le tri, puis filtrera les résultats.
La raison pour laquelle la dernière n'est pas recommandée est que SQL (et MySQL) ne garantissent pas l'ordre des résultats d'une sous-requête. Cependant, comme MySQL matérialise les sous-requêtes, les résultats sont vraiment corrects. Je n'aime pas utiliser des effets secondaires non documentés, qui peuvent changer d'une version à l'autre.