Petite optimisation SQL ?

WRInaute discret
Bonjour,

il me semble que je peux optimiser ma requête SQL.

Je dois afficher sur une page une liste d'utilisateurs avec leurs 3 derniers produits. J'ai une table contenant la liste des produits qui indique à qui appartient le produit et sa date d'ajout.

id_produit (clef primaire)
id_user
date

Aujourd'hui, je récupère *tous* les produits d'une liste d'utilisateurs:
SELECT * FROM produits WHERE id_user IN (...);

En PHP, je groupe ensuite les produits par utilisateur et je les classe par date pour ne prendre que les 3 derniers.

N'y a-t-il pas moyen de faire d'une pierre deux coups et d'indiquer à MySql que je ne souhaite récupérer que les 3 derniers produits ? Du genre avec GROUP BY ou DISTINCT ?

Merci de votre aide.
 
WRInaute occasionnel
Code:
SELECT * FROM produits WHERE id_user IN (...) ORDER BY date DESC LIMIT 0,3;
ORDER BY date DESC : on trie par date décroissante (de la plus récente à la plus ancienne)
LIMIT 0,3 : On ne veut que les 3 premiers résultats

Pour info : LIMIT 3,3 ressortira les résultats de 4 à 6 (le premier chiffre étant la position où l'on commence, le deuxième correspondant au nombre de résultats souhaités).
 
WRInaute accro
chtipepere a dit:
Code:
SELECT * FROM produits WHERE id_user IN (...) ORDER BY date DESC LIMIT 0,3;
ORDER BY date DESC : on trie par date décroissante (de la plus récente à la plus ancienne)
LIMIT 0,3 : On ne veut que les 3 premiers résultats

Pour info : LIMIT 3,3 ressortira les résultats de 4 à 6 (le premier chiffre étant la position où l'on commence, le deuxième correspondant au nombre de résultats souhaités).

Pas vraiment ce que voulait l'OP, là tu ne récupères que les 3 derniers produits en tout, pas les trois derniers de chaque utilisateur.

Plusieurs méthodes:

(je donne le code en perl, je ne suis pas très bon en php):

Code:
join " UNION ALL ",map {"SELECT * FROM produits WHERE id_user=? ORDER BY date DESC LIMIT 3"} @id_users

En gros, on fait une série de SELECT avec un LIMIT pour chaque utilisateur, et on regroupe tout ça avec des UNION ALL. Il me semble d'ailleurs que c'est un chouïa plus compliqué que ça, genre il faut faire un SELECT imbriqué sinon le LIMIT et le UNON ALL se tapent dessus.

Sinon en SQL pur:

Code:
SELECT * FROM produits p1 WHERE id_user IN (...) WHERE id_produit IN (SELECT id_produit FROM produits p2 WHERE id_user=p1.id_user ORDER BY date DESC LIMIT 3)

Sous toutes réserves, hein, pas testé, et aucune garantie sur la "performance" de la chose (surtout avec mysql).

Jacques.
 
WRInaute discret
Effectivement Jacques, ta proposition est ce que je souhaite faire.

Mais comme tu le soulignes, c'est la performance de ce genre de requête qui est inquiétant.

Je vais faire le test mais dans tous les cas je suppose qu'il est préférable de faire porter la charge par PHP plutôt que par MySql. D'autant plus que je suis hébergé en mutualisé et qu'en général le pb se trouve du coté de la bdd.

Merci
 
Nouveau WRInaute
Je vais faire le test mais dans tous les cas je suppose qu'il est préférable de faire porter la charge par PHP plutôt que par MySql. D'autant plus que je suis hébergé en mutualisé et qu'en général le pb se trouve du coté de la bdd.

... quoique avec ton " * from ", c'est à la fois le PHP et la BDD qui sont surchargés ... car la BDD doit recuperer et envoyer toutes tes données, mais ensuite, PHP doit aussi parser toutes tes données ... alors qu'avec une bonne requete SQL, la BDD ne t'envoie que les données qu'il faut et php fera moins d'itérations ...

Sinon, faut surtout avoir des index au bon endroit ... car sinon, recuperer tous le contenu de la BDD avec php et le parser avec php sera plus intéressant xD : des requetes optimisé sur une structure de BDD non optimisé c'est pire que tous...
 
WRInaute discret
Toujours déclarer les champs qu'on veut dans son select ;)
Ca te fait une petite optimisation déjà :p
 
Discussions similaires
Haut