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

PHP & Base de données Discussion :

Optimisation d'une requête [MySQL]


Sujet :

PHP & Base de données

  1. #1
    Membre éprouvé Avatar de renaud26
    Homme Profil pro
    Webmaster
    Inscrit en
    Mars 2003
    Messages
    1 365
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Webmaster

    Informations forums :
    Inscription : Mars 2003
    Messages : 1 365
    Par défaut Optimisation d'une requête
    Bonjour à tous,

    J'ai 3 tables (je simplifie et schématise):

    - produits :
    champs : id, reference, nom, prix
    clé primaire sur id

    - catégories :
    champs : id, nom
    clé primaire sur id

    - produits_categories :
    champs : produit_id, categorie_id
    clés sur produit_id et categorie_id

    Pour afficher une liste de produits avec le nom de leur catégorie, je fais la requête suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    SELECT p.id, p.reference, p.nom, p.prix, c.nom AS categorie
    FROM produits p LEFT OUTER JOIN produits_categories pc ON p.id = pc.produit_id
    LEFT OUTER JOIN categories c ON c.id = pc.categorie_id
    Mais avec 800 produits, ça rame un peu...
    Une idée pour améliorer cette requête ?
    Merci d'avance.

  2. #2
    Modérateur
    Avatar de sabotage
    Homme Profil pro
    Inscrit en
    Juillet 2005
    Messages
    29 208
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Juillet 2005
    Messages : 29 208
    Par défaut
    800 entrées c'est petit.
    Combien de temps mets ta requête a s'exécuter ?
    N'oubliez pas de consulter les FAQ PHP et les cours et tutoriels PHP

  3. #3
    Membre éprouvé Avatar de renaud26
    Homme Profil pro
    Webmaster
    Inscrit en
    Mars 2003
    Messages
    1 365
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Webmaster

    Informations forums :
    Inscription : Mars 2003
    Messages : 1 365
    Par défaut
    Bonjour,

    Près de 20 secondes...

  4. #4
    Membre chevronné
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2009
    Messages
    236
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Octobre 2009
    Messages : 236
    Par défaut
    A mon avis, ton problème ne vient à mon avis pas de ta requête, il y a eu un topic sur un peu le même soucis, ta connexion à ta base se fait par 'localhost' ou '127.0.0.1' ?

    Dans certains cas (allez savoir pourquoi) localhost peine à se connecter.

  5. #5
    Membre éprouvé Avatar de renaud26
    Homme Profil pro
    Webmaster
    Inscrit en
    Mars 2003
    Messages
    1 365
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Webmaster

    Informations forums :
    Inscription : Mars 2003
    Messages : 1 365
    Par défaut
    Bonjour,

    Non sur un serveur web 1 and 1...

  6. #6
    Expert confirmé
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Par défaut
    Est ce que tu as le même problème en local ? Si tel est le cas tu peux savoir où ça coince avec xdebug en activant le profiling (utilise webgrind pour parser les fichiers de profiling).

    Juste une question: pourquoi utilises-tu les outer join là ou des join simples suffiraient.
    Personnellement, je n'ai jamais rencontré de problèmes en utilisant cette forme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    SELECT A.id, B.name
    FROM `tableA` as A
    JOIN `tableB` as B 
    ON (A.id=B.tableA_id);

  7. #7
    Modérateur
    Avatar de sabotage
    Homme Profil pro
    Inscrit en
    Juillet 2005
    Messages
    29 208
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Juillet 2005
    Messages : 29 208
    Par défaut
    Tu peux utiliser une requête EXPLAIN pour voir.
    N'oubliez pas de consulter les FAQ PHP et les cours et tutoriels PHP

  8. #8
    Membre éprouvé Avatar de renaud26
    Homme Profil pro
    Webmaster
    Inscrit en
    Mars 2003
    Messages
    1 365
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Webmaster

    Informations forums :
    Inscription : Mars 2003
    Messages : 1 365
    Par défaut
    A Benjamin Delespierre :

    Déjà, en utilisant JOIN au lieu de OUTER JOIN je gagne un temps considérable.
    Merci à toi.

    A Sabotage : je ne connais pas explain, je vais regarder la doc.

  9. #9
    Membre éprouvé Avatar de renaud26
    Homme Profil pro
    Webmaster
    Inscrit en
    Mars 2003
    Messages
    1 365
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Webmaster

    Informations forums :
    Inscription : Mars 2003
    Messages : 1 365
    Par défaut
    J'ai encore besoin de vos lumières...
    Si je reprends ma requête :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    SELECT p.id, p.nom, c.nom AS categorie
    FROM produits p JOIN produits_categories pc ON p.id = pc.produit_id
    JOIN categories c ON c.id = pc.categorie_id
    Elle fonctionne bien. Mais j'ai un petit souci, dans le cas où un produit est attaché à plusieurs catégories, il apparaît autant de fois dans la liste :

    Table produits
    id | nom |
    1 | vélo |
    2 | scooter |
    3 | voiture |
    4 | trottinette

    Table catégories
    id | nom
    1 | véhicules
    2 | jouet

    table produits_categories
    produit_id | categories_id
    1 | 1
    2 | 1
    3 | 1
    4 | 1
    4 | 2

    Dans ce cas, le produit "trottinette" s'affichera 2 fois. Comment faire en sorte qu'il ne s'affiche qu'une fois et que la ligne catégorie affiche la première des deux ?

  10. #10
    Expert confirmé
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Par défaut
    Mets une clause distinct.

  11. #11
    Membre éprouvé Avatar de renaud26
    Homme Profil pro
    Webmaster
    Inscrit en
    Mars 2003
    Messages
    1 365
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Webmaster

    Informations forums :
    Inscription : Mars 2003
    Messages : 1 365
    Par défaut
    Bonjour,

    Déjà essayé : sans succès.

  12. #12
    Membre Expert Avatar de RunCodePhp
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    2 962
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations forums :
    Inscription : Janvier 2010
    Messages : 2 962
    Par défaut
    Salut

    Près de 20 secondes...
    Comment as tu obtenu ce temps ?
    Est-ce vraiment uniquement cette requête qui met 20s ou c'est l'affichage de la page qui entre autre exécute la requête ?

    Puis depuis combien de temps as tu remarqué cette lenteur ?
    N'y a t-il pas eu des modifs effectuées qui pourrait laisser croire que ???

    Aussi, tu n'as pas répondu à la question si tu remarquais le même problème en local, c'est pourtant important, ça peu donner une piste.

    Il serait bon d'exporter ta Bdd, l'importer chez toi dans PhpMyAdmin (par exemple).
    Ca fera déjà une sauvegarde, puis lancer la même requête, et voir ce que ça donne.

    Aussi, as tu regarder (PhpMyAdmin toujours) si cette contient des pertes (les autres table par la même occasion).
    N'y t-il pas d'autres tables qui semblerait anormal ?
    PhpMyAdmin propose de faire certaine manip. sur les tables, comme optimisation, réparation, etc ..., et bien bien exécute les (Backup avant, cela va sans dire ).


    Tu pourrais aussi, ne serait-ce vite fait, mettre des repères de temps (fonction microtime), au moins entre l'exécution de la requête.
    Si ce n'est pas juste la requête qui cause problème, rajouter des repères à des phases clés dans ton code pourrait déceler certaines parties louches/douteuses.

    De même, as tu exploiter un outil genre FireDebug qui fourni des temps de chargement de tous les élément que compose la page Web.
    Même si c'est que coté client, on obtient les temps de réponse du serveur.


    Optimiser les tables, le SQL, les index, etc ... sera en toute évidence un bénéfice.
    Mais 20s c'est long, et il y a forcément un problème, où du moins une explication, donc même en optimisant, le problème restera entier.
    Essai au moins de localiser au mieux où se situe la lenteur.

  13. #13
    Membre éprouvé Avatar de renaud26
    Homme Profil pro
    Webmaster
    Inscrit en
    Mars 2003
    Messages
    1 365
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Webmaster

    Informations forums :
    Inscription : Mars 2003
    Messages : 1 365
    Par défaut
    Bonjour et merci pour ta réponse détaillée.

    Je viens de créer ce script, donc, la lenteur, c'est depuis la 1ère exécution.
    En local, cela va un peu plus vite, mais c'est pas terrible.
    Mais je devrais dire "c'était", car le simple fait d'utiliser JOIN à la place de LEFT OUTER JOIN a divisé le temps par 4 ! Bon à savoir.

    J'ai tenté d'utiliser Firebug, mais mon FF ne l'apprécie pas du tout...
    Et, oui j'ai fait des optimize sur les tables concernées.

    Cette partie de mon post est donc résolue. J'ai ensuite posé une seconde question concernant la requête elle-même et comment éviter les doublons dans l'affichage qui se produisent même avec DISTINCT.

    Bonne journée.

  14. #14
    Membre Expert Avatar de RunCodePhp
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    2 962
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations forums :
    Inscription : Janvier 2010
    Messages : 2 962
    Par défaut
    Mais je devrais dire "c'était", car le simple fait d'utiliser JOIN à la place de LEFT OUTER JOIN a divisé le temps par 4 ! Bon à savoir.
    C'est bon à savoir effectivement.

    En tout cas, de mon coté je privilégie toujours une jointure stricte (JOIN), car dans la majorité des cas on ne souhaite pas obtenir les données NULL ou non présentes par rapport à la jointure.

    Disons qu'il faut percevoir ça comme non pas une optimisation, mais bel et bien de 2 besoins/résultat potentiellement différents, donc l'un ne remplace pas l'autre.

    Mais même divisé par 4, ça sous entend que ça fait 5 secondes, ça me semble encore beaucoup.
    Il y a peut être beaucoup de catégories.
    C'est quand même bizarre, car MySQL est théoriquement capable de travailler avec plusieurs milliers de lignes, sans pourtant prendre plusieurs secondes pour 1 (petite) requête.

    As tu des INDEX au niveau de la table "categories" et "produits" ?


    J'ai ensuite posé une seconde question concernant la requête elle-même et comment éviter les doublons dans l'affichage qui se produisent même avec DISTINCT.
    Si je ne dis pas de bêtise, un GROUP BY p.id devrait faire l'affaire.

    Toujours si je ne dis pas de bêtise, le DISTINCT agit uniquement sur les valeurs des champs au niveau du SELECT, et élimine les doublons si tous les noms identiques.

    DISTINCT ne fonctionne pas car le nom du champ c.nom est différent pour chaque p.id, même pour 2 ou 3, etc ... p.id identiques.
    Normal, un produit est lié à plusieurs catégories différentes, donc de nom de catégories différentes.

    En utilisant un GROUP BY, on désigne explicitement le ou les champs où doivent s'appliquer le regroupement.

  15. #15
    Membre éprouvé Avatar de renaud26
    Homme Profil pro
    Webmaster
    Inscrit en
    Mars 2003
    Messages
    1 365
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Webmaster

    Informations forums :
    Inscription : Mars 2003
    Messages : 1 365
    Par défaut
    Merci RunCodePhp !

    C'est exactement ça : étant donné que dans la table produits_categories j'ai un doublon sur le champ produit_id, j'ai fait un GROUP BY pc.produit_id et c'est nickel.

    Encore merci et bonne journée.

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

Discussions similaires

  1. Optimisation d'une requête
    Par Louis-Guillaume Morand dans le forum MS SQL Server
    Réponses: 5
    Dernier message: 20/12/2005, 18h21
  2. Optimisation d'une requête d'insertion
    Par fdraven dans le forum Oracle
    Réponses: 15
    Dernier message: 01/12/2005, 14h00
  3. Optimisation d'une requête patchwork
    Par ARRG dans le forum Langage SQL
    Réponses: 1
    Dernier message: 11/09/2005, 15h23
  4. optimisation d'une requête avec jointure
    Par champijulie dans le forum PostgreSQL
    Réponses: 8
    Dernier message: 07/07/2005, 09h45
  5. [DB2] Optimisation d'une requête
    Par ahoyeau dans le forum DB2
    Réponses: 7
    Dernier message: 11/03/2005, 17h54

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