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

MySQL Discussion :

Optimisation d'une requête


Sujet :

MySQL

  1. #1
    Membre extrêmement actif Avatar de lodan
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    2 064
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 064
    Points : 682
    Points
    682
    Par défaut Optimisation d'une requête
    Bonjour,

    Sur un formulaire, je saisi le début d'un nom et avec ajax j'alimente une liste de sélection.

    Je me pose des questions sur la meilleur façon d'optimiser mes tables pour être le plus performant possible dans la lecture de mes tables.

    J'ai 2 tables : clients et clients_adresses.

    L'identifiant commun au 2 tables est "id_client".

    Dans ma table clients j'ai 3 champs sur lesquels je souhaite faire ma recherche de nom :
    - client_raison_sociale
    - client_nom
    - client_prenom

    Je concataine les 3 champs pour pouvoir faire une recherche sur "dupont philippe"

    Ma table clients a un index constitué des champs client_raison_sociale, client_nom, client_prenom

    Voici ma requête

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    SELECT clients.id_client, client_raison_sociale, client_service, client_nom, client_prenom, client_code_postal, client_ville
    FROM clients
    LEFT OUTER JOIN clients_adresses
    USING ( id_client )
    WHERE CONCAT(client_raison_sociale, ' ', client_nom, ' ', client_prenom) LIKE '%dupont philippe%'
    AND (
    CURDATE( ) <= client_adr_date_fin
    OR client_adr_date_debut <= CURDATE( )
    AND client_adr_date_fin = '0000-00-00'
    )
    ORDER BY client_raison_sociale, client_nom, client_prenom
    limit 0, 10
    Ma base fait 400 000 enregistrements et lorsque je fais une requête le temps de réponses est de plus de 1" voir 2".

    Comment optimiser ma requête ?

    Merci d'avance.
    Y a pas, plus on fait, plus on sait. Plus on cherche, plus on sait chercher. Maintenant quant à trouver, c'est autre chose.

  2. #2
    ced
    ced est déconnecté
    Rédacteur/Modérateur

    Avatar de ced
    Homme Profil pro
    Gestion de bases de données techniques
    Inscrit en
    Avril 2002
    Messages
    6 016
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : Gestion de bases de données techniques
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Avril 2002
    Messages : 6 016
    Points : 23 705
    Points
    23 705
    Par défaut
    Bonjour,

    2 petites pistes vite fait :
    1. CURDATE( ) BETWEEN client_adr_date_debut AND client_adr_date_fin
    2. client_adr_date_fin IS NULL


    Ensuite, la concaténation augmente sûrement le temps de traitement et il faudrait peut-être la remplacer par une recherche un peu plus "décomposée".

    ced
    Rédacteur / Modérateur SGBD et R
    Mes tutoriels et la FAQ MySQL

    ----------------------------------------------------
    Pensez aux balises code et au tag
    Une réponse vous a plu ? N'hésitez pas à y mettre un
    Je ne réponds pas aux questions techniques par message privé, les forums sont là pour ça

  3. #3
    Membre émérite

    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    3 995
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 995
    Points : 2 528
    Points
    2 528
    Par défaut
    Plusieurs choses :

    • Le fait que tu utilises une fonction (concat) va faire que MySQL ne va pas utiliser d'index. Pas idéal, niveau performance. Tu n'en as pas vraiment besoin puisque tu concatènes avec des espaces, et que tu mets un espace au milieu de ta chaine. Tu pourrais alors ajouter un index sur ces 3 champs.
    • Si tu as toujours une adresse pour chaque client, tu peux enlever le "OUTER"
    • MySQL n'aime pas les OR. Si tu as un moyen de t'en passer, ça vaut mieux. Sinon, il risque de ne pas appliquer d'index aux clauses concernées.


    L'objectif, en matière d'optimisation de requête SQL, ce n'est pas seulement de restreindre le nombre de lignes à traiter, mais aussi le plus possible les faire traiter à travers d'index.

  4. #4
    Membre extrêmement actif Avatar de lodan
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    2 064
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 064
    Points : 682
    Points
    682
    Par défaut
    J'ai fait les modifs préconisées dans la requête.

    Un index avec les 3 champs existe déjà (voir mon 1er post).
    Un index sur client_adr_date_debut existe

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    SELECT clients.id_client, client_raison_sociale, client_service, client_nom, client_prenom, client_code_postal, client_ville
    FROM clients
    LEFT JOIN clients_adresses
    USING ( id_client )
    WHERE CONCAT( client_raison_sociale, ' ', client_nom, ' ', client_prenom ) LIKE '%dupont philippe%'
    AND (
    CURDATE( )
    BETWEEN client_adr_date_debut
    AND client_adr_date_fin
    AND client_adr_date_fin IS NOT NULL
    )
    ORDER BY client_raison_sociale, client_nom, client_prenom 
    LIMIT 0,10
    La requête dure 1.6400 sec pour un résultat de 6 enregistrement

    J'ai fait un explain dont voici le résultat
    [IMG]http://www.developpez.net/forums
    /attachment.php?attachmentid=63200&stc=1&d=1275462221[/IMG]

    Le modifs n'ont donc pas apportées le résultat que j'escomptais.

    Une autre piste ?
    Images attachées Images attachées  
    Y a pas, plus on fait, plus on sait. Plus on cherche, plus on sait chercher. Maintenant quant à trouver, c'est autre chose.

  5. #5
    Membre extrêmement actif Avatar de lodan
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    2 064
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 064
    Points : 682
    Points
    682
    Par défaut
    Y aurait-il un intérêt à créer un champ dans la table concaténant sans espace la raison sociale, le nom et le prénom et de faire une recherche dessus avec une expression sans espace ?
    Y a pas, plus on fait, plus on sait. Plus on cherche, plus on sait chercher. Maintenant quant à trouver, c'est autre chose.

  6. #6
    Membre confirmé
    Avatar de argoet
    Inscrit en
    Mai 2002
    Messages
    582
    Détails du profil
    Informations forums :
    Inscription : Mai 2002
    Messages : 582
    Points : 562
    Points
    562
    Par défaut
    Quelques Remarques en passant :

    Pourquoi faire une rechecrche sur 3 champs concatene si vous rechercher "dupont" et "philippe"
    n'est il pas possible d'associer dupont au nom et philippe au prenom ?


    Ma table clients a un index constitué des champs client_raison_sociale, client_nom, client_prenom
    Raison sociale n'etant absolument pas discriminant vous avez tout interet à créer votre index sur 1:le nom 2:le Prenom et(ou pas) eventuelement la raison sociale

    le fait de faire un "like %XXX%" va forcement réaliser un "access full" sur la table donc au final votre index ne sert à rien dans la présente requete
    Signé : Capitaine Jean-Luc Picard

  7. #7
    Membre extrêmement actif Avatar de lodan
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    2 064
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 064
    Points : 682
    Points
    682
    Par défaut
    Merci, mais ... sur mon formulaire, j'ai 3 champs :

    - client_raison_sociale
    - client_nom
    - client_prenom

    L'objectif est de savoir si le client existe déjà et je ne contrôle pas dans quel champ de formulaire l'utilisateur commencera sa recherche.

    Supposons qu'il commence à saisir "Dupont" dans le champ client_nom, je vais avoir une liste (que je limite) des dupont existant. il continue sa saisir en mettant "Dupont ph", je ne verrai alors que les "Dupont ph".

    L'utilisateur fait donc une recherche dans un seul champ pour retrouver un client.

    Lorsqu'il le choisi dans la liste, je réparti alors la dénomination du client choisi sur le formulaire dans les bons champ.
    Y a pas, plus on fait, plus on sait. Plus on cherche, plus on sait chercher. Maintenant quant à trouver, c'est autre chose.

  8. #8
    Membre confirmé
    Avatar de argoet
    Inscrit en
    Mai 2002
    Messages
    582
    Détails du profil
    Informations forums :
    Inscription : Mai 2002
    Messages : 582
    Points : 562
    Points
    562
    Par défaut
    Dans ce cas , vous pouvez alors construire dynamiquement votre requete en fonction des champs qui ont été saisies
    je sais , le code sera forcement plus lourd , mais le resultat a priori plus rapide
    Signé : Capitaine Jean-Luc Picard

  9. #9
    Membre extrêmement actif Avatar de lodan
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    2 064
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 064
    Points : 682
    Points
    682
    Par défaut
    Citation Envoyé par argoet Voir le message
    Dans ce cas , vous pouvez alors construire dynamiquement votre requete en fonction des champs qui ont été saisies
    je sais , le code sera forcement plus lourd , mais le resultat a priori plus rapide
    J'ai essayé de comprendre comment faire en dynamique, mais je ne vois pas.

    Comme je le dis dans mon précédent post, je ne sais pas si ce que l'utilisateur écris est une raison sociale, un nom ou un prénom, donc je suis obligé de regarder dans les 3 champs concaténé non ????
    Y a pas, plus on fait, plus on sait. Plus on cherche, plus on sait chercher. Maintenant quant à trouver, c'est autre chose.

  10. #10
    Membre confirmé
    Avatar de argoet
    Inscrit en
    Mai 2002
    Messages
    582
    Détails du profil
    Informations forums :
    Inscription : Mai 2002
    Messages : 582
    Points : 562
    Points
    562
    Par défaut
    Citation Envoyé par lodan Voir le message
    Supposons qu'il commence à saisir "Dupont" dans le champ client_nom, je vais avoir une liste (que je limite) des dupont existant. il continue sa saisir en mettant "Dupont ph", je ne verrai alors que les "Dupont ph"
    Citation Envoyé par lodan Voir le message
    Comme je le dis dans mon précédent post, je ne sais pas si ce que l'utilisateur écris est une raison sociale, un nom ou un prénom, donc je suis obligé de regarder dans les 3 champs concaténé non ????
    Ceci est assez contradictoire
    Que faites vous si vous commencer à saisir dans le champ nom puis dans le champ prenom la concatenation vous donnera et non pas Votre code dans ce cas devrait proche de ceci pour gérer tous les cas possible
    Construction dynamique de la requete en fonction des champs rensignés
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    --Si :champ_rs n'est pas vide ajouter à la requete 
    And instr(client_raison_sociale||client_nom||client_prenom, :champ_rs) > 0
    --Si :champ_nom n'est pas vide ajouter à la requete 
    And instr(client_raison_sociale||client_nom||client_prenom, :champ_nom) > 0
    --Si :champ_prenom n'est pas vide ajouter à la requete 
    And instr(client_raison_sociale||client_nom||client_prenom, :champ_prenom) > 0
    ou bien
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    And ( instr(client_raison_sociale||client_nom||client_prenom, :champ_rs)     > 0 or :champ_rs     is null )
    And ( instr(client_raison_sociale||client_nom||client_prenom, :champ_nom)    > 0 or :champ_nom    is null )
    And ( instr(client_raison_sociale||client_nom||client_prenom, :champ_prenom) > 0 or :champ_prenom is null )
    Signé : Capitaine Jean-Luc Picard

  11. #11
    Membre extrêmement actif Avatar de lodan
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    2 064
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 064
    Points : 682
    Points
    682
    Par défaut
    Merci

    Si l'utilisateur (uniquement du personnel interne) fait une recherche en saisissant dans le champ nom, il saisira (c'est une convention) toujours dans le même sens raison sociale (s'il y en a une), le nom puis le prénom.

    Idem dans le champ raison sociale.
    Y a pas, plus on fait, plus on sait. Plus on cherche, plus on sait chercher. Maintenant quant à trouver, c'est autre chose.

  12. #12
    Membre extrêmement actif Avatar de lodan
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    2 064
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 064
    Points : 682
    Points
    682
    Par défaut
    La solution est ici et .

    Et dans mon cas c'est amplement suffisant.
    Y a pas, plus on fait, plus on sait. Plus on cherche, plus on sait chercher. Maintenant quant à trouver, c'est autre chose.

+ 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