Requete pour faire un classement : lenteur !

Requete pour faire un classement : lenteur ! - SQL/NoSQL - Programmation

Marsh Posté le 02-09-2009 à 16:12:00    

Bonjour à tous,

 

je sollicite votre aide sur un point de performance.
Je souhaite sur un de mes sites, faire un classement top 10 des membres suivant leur nombre de points gagnés en participant au site.

 

Voici ma requete sous MySQL:

Code :
  1. SELECT
  2.         nom,
  3.         prenom,
  4.         SUM(point.point) as nbr_points
  5. FROM
  6.         membre
  7.         INNER JOIN point ON point.id_membre = membre.id_membre
  8. GROUP BY
  9.         membre.id_membre
  10. ORDER BY
  11.         nbr_points DESC
  12. LIMIT
  13.         0, 10


Pourquoi une table point? c'est pour pouvoir faire des historiques, des stats...etc.
Le probleme de cette requete est que ca calcule le nombre de points de tout le monde avant de me sortir le top 10. Plus il y a de membres, plus ca va ramer. Et plus il y a de points, plus ca rame également (je suppose).

 

Ma requete est syntaxiquement juste et je ne vois pas vraiment comment faire pour l'optimiser.

 

Question: est-il possible de faire mieux?

 

Merci beaucoup.


Message édité par welcominh le 02-09-2009 à 16:12:42

---------------
Direct-download.com, le moteur de recherche pour Mega
Reply

Marsh Posté le 02-09-2009 à 16:12:00   

Reply

Marsh Posté le 02-09-2009 à 16:52:09    

je vois pas vraiment comment tu peux faire autrement. sit u veux le top 10, t'es bien obligé de calculer pour tout le monde pour savoir qui est dans le top 10... :spamafote:

Reply

Marsh Posté le 02-09-2009 à 17:03:07    

C'est ce que je pensais aussi.
Bon bah si c'est ce qu'il y a de mieux, je vais devoir m'en contenter  :ange:

 

Merci pour ta contribution pataluc :)


Message édité par welcominh le 02-09-2009 à 17:03:23

---------------
Direct-download.com, le moteur de recherche pour Mega
Reply

Marsh Posté le 03-09-2009 à 02:17:52    

Le champ id_membre est bien la clé primaire de la table membre ?
 
Un membre peut-il apparaitre plusieurs fois dans la table point ? J'espère que non sinon la table point est complètement inutile.
 
Dans tous les cas, il faut que le champ id_membre soit défini en tant que :

  • clé primaire(donc index unique) dans la table membre
  • index dans la table point


Tu peux faire un "explain" de ta requête ?


Message édité par cezium134 le 03-09-2009 à 02:24:01
Reply

Marsh Posté le 03-09-2009 à 11:04:36    

Oui le champ id_membre est bien la clé primaire de la table membre.
 
Oui un membre peut apparaitre plusieurs fois dans la table point. Niveau intéret, je ne trouve pas cela inutile. Car comme expliqué, cela permet de tracer les points pour faire des stats. Par exemple, pour chaque "lot de points" gagnés, on peut déterminer l'action réalisée pour gagner ces points, sur quelle page ces points ont été gagnés, l'heure au moment où ces points ont été gagnés...etc.
 
Le champ id_membre n'est par contre pas en index dans la table point. Je vais le faire de ce pas.
Voici le résultat explain de la requête, qui au passage de change pas après l'ajout de l'index:
 
http://img522.imageshack.us/img522/5097/classementsansindex.jpg


---------------
Direct-download.com, le moteur de recherche pour Mega
Reply

Marsh Posté le 03-09-2009 à 13:28:34    

welcominh a écrit :

Oui le champ id_membre est bien la clé primaire de la table membre.
 
Oui un membre peut apparaitre plusieurs fois dans la table point. Niveau intéret, je ne trouve pas cela inutile.  


 
C'est ce que je voulais dire en fait ;)
 
Sinon, l'ajout de l'index permet à la jointure d'être plus rapide mais c'est certainement insignifiant dans ton cas.
 
Je ne vois pas d'autre solution si tu gardes ces 2 tables. L'autre moyen serait de construire une table d'agrégat.


Message édité par cezium le 03-09-2009 à 13:28:54
Reply

Marsh Posté le 03-09-2009 à 14:47:05    

Vu le truc, je proposerais bien de dénormaliser  :o .
 
Au choix - voir entre autres suivant la fréquence de MàJ des points :

  • Transforme ta table POINTS en HIST_POINTS, et crée un champ MEMBRES.points (à mettre à jour à chaque modification)
  • Crée une table de cumul POINTS_MEMBRES (Id_membre, total_points). Tu peux la mettre à jour en temps réel ou tous les x minutes.
  • Tu peux aussi partir du principe que le classement évolue relativement peu. => Tu enregistre les ID des X premiers membres, et tu fais ton SELECT en limitant à ces membres. Reste à mettre à jour régulièrement le classement.
  • Un mélange de ces solutions...

Reply

Marsh Posté le 03-09-2009 à 17:19:21    

Sinon ça va pas ramer du tout et voilà ton problème est résolu.
Par contre se branler la nouille en forçant le filesort, faut pas chercher plus loin pourquoi ça chie.
 
Bref préjugé initial foireux, evil toussa

Reply

Marsh Posté le 04-09-2009 à 01:27:28    

Merci beaucoup pour votre contribution.
Mention spéciale à macgawel :) Pas bête du tout la dénormalisation ! J'y avais pas pensé. Je vais opter pour les 2 premieres solutions qui me paraissent faciles et légères en ressources.
 
Thks again !


---------------
Direct-download.com, le moteur de recherche pour Mega
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed