IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage SQL Discussion :

[MySQL] Optimisation requête, affichage lent


Sujet :

Langage SQL

  1. #1
    Membre régulier
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Décembre 2006
    Messages
    255
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Décembre 2006
    Messages : 255
    Points : 100
    Points
    100
    Par défaut [MySQL] Optimisation requête, affichage lent
    Bonsoir à tous,

    j'ai un petit problème de performances pour afficher quelques informations à l'aide d'une requête (ou plusieurs ?) SQL sur une base MySql.

    En fait j'ai la table suivante :

    Performance(id, joueur, circuit, temps, pays, taille, date);

    Cela concerne en fait des joueurs qui envoi leur performance sur un circuit après avoir jouer.
    Sur un circuit, les 10 meilleurs joueurs (meilleurs temps) gagnent respectivement 10pts, 9pts, 8pts,... ,1pt.

    Ce que je voudrais c'est afficher un classement, et donc afficher pour chacun des joueurs: son nom, son pays, son total de points, son nombre total de performances, son éfficacité (nb tot de pts / nb tot de demos), son nombre de médaille d'or, d'argent et de bronze.

    J'y suis arrivé mais je fait ça d'une manière assez "bourrine" (j'utilise 4 requêtes, avec des boucles while imbriquées etc), et donc la page met bien 3 à 4s pour s'afficher, et il n'y a pour le moment que 30 joueurs, donc ça risque de devenir encore plus problèmatique lorsqu'il y en aura d'avantage.

    PS : je peux éventuellement fournir le code php que j'ai fait mais ce n'est pas très propre :/

    Merci à tous ceux qui prendrons du temps pour m'aider.


  2. #2
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 856
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 856
    Points : 52 992
    Points
    52 992
    Billets dans le blog
    6
    Par défaut
    Mysql n'implémente pas les fonctions de fenêtrage comme RANK, ROW_NUMBER, permettant de faire ceci de manière efficace et rapide en une seule requête. Je doute fort que vous puissiez le faire efficacement sans. Au mieux, imbriquez vos 4 requêtes en une seule, sinon, changez de SGBDR !

    A +

  3. #3
    Membre actif
    Homme Profil pro
    Analyst
    Inscrit en
    Juillet 2008
    Messages
    150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations professionnelles :
    Activité : Analyst
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2008
    Messages : 150
    Points : 217
    Points
    217
    Par défaut
    Je ne connais pas PHP.
    En revanche, pour résoudre ce genre de problème en Java, j'alimente des objets en faisait un (ou plusieurs) SELECT plus global et après je parcours les objets.

  4. #4
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 048
    Points
    34 048
    Billets dans le blog
    14
    Par défaut
    Montre nous tes requêtes, on verra si on peut optimiser ça.
    Bien sûr ta table est correctement indexée ?

  5. #5
    Membre régulier
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Décembre 2006
    Messages
    255
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Décembre 2006
    Messages : 255
    Points : 100
    Points
    100
    Par défaut
    Merci pour vos réponses.

    Je n'ai jamais utilisé les fonctions comme RANK ou ROW_NUMBER, mais de toute façon je n'ai le choix qu'entre MySql et PostGres et j'ai déjà tout fait le site avec MySql.

    Alimenter des objets j'y avait pensé aussi, mais parcourir des tableaux en PHP ça peut être long (?) et puis il faut tout que je réécrive le code :/


    Sinon j'ai seulement un index sur la clé primaire (normal)
    En gros mon algo ressemble à ça (j'ai un peu simplifié) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
    $sql1 = Une requete pour selectionner tous les joueurs
    $sql2 = Une requete pour selectionner tous les circuits
    Pour chaque joueur
     Pour chaque circuit
      $sql3 = SELECT temps,pays,nom FROM dl_Demos WHERE joueur='".$row[0]."' AND map='".$row3[0]."'
      $sql4 = SELECT MIN(temps) FROM dl_Demos WHERE map='".$row3[0]."'
      $sql5 = SELECT joueur FROM dl_Demos WHERE map='".$row3[0]."' ORDER BY temps ASC LIMIT 0,3
      Pour chacun des 3 joueurs sélectionnés dans $sql5
       Je le compare au joueur actuel ($sql1)
        si il est premier alors m_or++
        si il est deuxieme alors m_argent++
        si il est troisieme alors m_bronze++
       fin si
      fin pour
      Je calcul les points ($points = $points + (temps du joueur / temps du meilleur joueur)*10
     fin pour
     Ensuite étant donné que je veux que mon tableau html puisse etre trié
     en cliquant sur le nom de colonnes, je créer un tableau en php contenant
     comme indice une ligne de tableau (<tr><td>pays</td><td>nom</td>...</tr>)
     et comme valeur la valeur de cette ligne qui correspond
     à la colonne que l'utilisateur veut trier (genre "France" si 
     c'est le pays du joueur correspondant à la ligne en indice).
    fin pour
    Ensuite je fait un asort ou un arsort sur ce tableau suivant le
    choix de l'utilisateur (tri ASC ou DSC). Puis j'affiche le tableau 
    (foreach ($tablo as $key => $val) { affichage }
    Vous voyez qu'avec une trentaine de joueur et de circuit ça fait pas mal de boucles :/
    Mais bon là je crois que je vais réussir à simplifier un peu, je suis en train de tout refaire sur papier.
    Néanmoins si vous avez des idées

    Merci !

  6. #6
    Membre régulier
    Inscrit en
    Octobre 2004
    Messages
    154
    Détails du profil
    Informations forums :
    Inscription : Octobre 2004
    Messages : 154
    Points : 110
    Points
    110
    Par défaut
    Bonjour,

    As tu un lien entre toutes ces tables? Un id circuit par exemple qui serait croisé avec la map et le joueur?

    As tu un fais un schéma?


    Portekoi

  7. #7
    Membre régulier
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Décembre 2006
    Messages
    255
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Décembre 2006
    Messages : 255
    Points : 100
    Points
    100
    Par défaut
    J'avais juste fait une modélisation rapide sur papier, mais ça fait longtemps (~ 4 ans), donc je ne m'y connaissait bien moins que maintenant, d'ailleur sur free il y avait que MySql à cette époque, c'est pour ca que je n'ai pas utiliser Postgres.


    En fait la map c'est le circuit, j'avais mis circuit pour simplifer mais tu peuts remplacer circuit pas map

    Sinon j'ai juste 2 tables :
    dl_Demos(id,nom,joueur,map,temps,pays,taille,date)
    dl_Maps(id,nom,createur,taille,date)

    Je n'ai pas de table joueur, je n'ai besoin que du nom, mais je peux en créer une si il faut, d'ailleur actuellement je stock leur mails (lorsqu'ils upload une demo) dans un fichier texte, je pourrais le stocker dans cette table.

  8. #8
    Membre régulier
    Profil pro
    INGENIEUR DE RECHERCHE
    Inscrit en
    Février 2003
    Messages
    74
    Détails du profil
    Informations personnelles :
    Âge : 57
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : INGENIEUR DE RECHERCHE

    Informations forums :
    Inscription : Février 2003
    Messages : 74
    Points : 87
    Points
    87
    Par défaut
    Bonjour,

    Suggestion :
    redessiner les tables en distinguant les informations de jeux de celles appartenant au joueur.
    Définir les attributs de recherche comme clés.
    Il doit être possible de faire une seule requête et de simplifier le code.

    Voilà sans en savoir plus sur le domaine.

    Spiale

  9. #9
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 048
    Points
    34 048
    Billets dans le blog
    14
    Par défaut
    Autre suggestion :
    Ajouter une notion de classement dans la table dl_Demos :
    dl_Demos(id,nom,joueur,map,temps,pays,taille,date, place)

    On utilisera aussi une table de classement :
    Classement(place, idDemo)
    place est un entier auto-incrémenté et idDemo est une clé étrangère qui accueillera l'id de dl_Demos.

    Procédure de classement, en supposant qu'on ne s'intéresse qu'à ceux qui obtiennent des points, donc les dix premiers, à utiliser après chaque ajout d'enregistrement dans dl_Demos (ou seulement si le temps réalisé est parmi les dix meilleurs du circuit) :
    1) Vider la table Classement et mettre l'auto-increment à zéro
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    TRUNCATE Classement;
    ALTER TABLE Classement AUTO_INCREMENT = 0;
    2) Insérer dans la table Classement les dix meilleurs du circuit qui vient d'être réalisé :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    INSERT INTO Classement(idDemo)
    SELECT idDemo
    FROM dl_Demos
    WHERE map = [idMap] // <== requête à paramétrer dans le programme java
    ORDER BY temps
    LIMIT 10
    3) Vider les places existantes du circuit qui vient d'être joué dans la table dl_Demos
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    UPDATE dl_Demos
    SET place = NULL
    WHERE map = [idMap]
    4) Mettre à jour les places avec le nouveau classement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    UPDATE dl_Demos d
    SET place = (
      SELECT place
      FROM Classement c
      WHERE d.idDemo = c.idDemo
    )
    Il est beaucoup plus facile ensuite de récupérer le classement de chaque circuit et de calculer les points des joueurs et le nombre de leurs médailles.

    1) Les dix premiers de chaque circuit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    SELECT map, joueur, place
    FROM dl_Demos
    WHERE place IS NOT NULL
    ORDER BY map, place
    En une seule requête tu as toutes les infos nécessaires. Si tu en fais une vue, tu peux l'interroger directement.
    Appelons la vue : 'TopTen'...

    2) Classement des joueurs selon le total de leurs points :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    SELECT joueur, SUM(11 - place) AS TotalPoints
    FROM TopTen
    GROUP BY joueur
    ORDER BY TotalPoints DESC
    3) Classement des joueurs selon le nombre de médaille d'or :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT joueur, COUNT(*) AS NbOr
    FROM TopTen
    WHERE place = 1
    GROUP BY joueur
    ORDER BY NbOr DESC
    Idem pour les autres médailles.

    A toi de continuer...
    Bon courage.

  10. #10
    Membre régulier
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Décembre 2006
    Messages
    255
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Décembre 2006
    Messages : 255
    Points : 100
    Points
    100
    Par défaut
    Merci pour vos réponses.

    Très bonne idée la table classement.
    Je n'avais pas pensé au SELECT dans le INSERT

    J'ai implémenté l'insertion et la mise à jour, tout fonctionne parfaitement.

    Il me reste plus qu'a afficher ce que je veux avec les requêtes de sélection, qui devraient être en effet beaucoup plus simple maintenant.

    Je vais aussi créer une table joueur pour m'éviter d'écrire dans un fichier texte à chaque upload.

    En tous cas merci. vraiment

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [MySQL] Optimisation requête SELECT
    Par GyZmoO dans le forum Requêtes
    Réponses: 3
    Dernier message: 22/10/2009, 17h24
  2. optimisation requête mysql
    Par ionesco dans le forum Requêtes
    Réponses: 1
    Dernier message: 08/10/2009, 12h14
  3. Réponses: 6
    Dernier message: 25/09/2009, 11h10
  4. [MySQL] [MySQL] Optimisation de requête
    Par Falistos dans le forum PHP & Base de données
    Réponses: 4
    Dernier message: 30/06/2009, 08h51
  5. Requête trop lente, comment l'optimiser?
    Par getz85 dans le forum Langage SQL
    Réponses: 19
    Dernier message: 29/01/2008, 13h40

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo