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

Requêtes MySQL Discussion :

Aide à l'optimisation d'une requête composée de plusieurs LEFT JOIN


Sujet :

Requêtes MySQL

  1. #1
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2016
    Messages
    74
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Algérie

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2016
    Messages : 74
    Points : 67
    Points
    67
    Par défaut Aide à l'optimisation d'une requête composée de plusieurs LEFT JOIN
    Bonjour à tous

    Je possède une base de données de courriers (traitées/non traitées) pour chaque direction (représentée par une personne), cette direction comporte plusieurs sous-directions (destinations)

    Exp:
    la direction A (représentée par le directeur X) comprend plusieurs sous-directions a1, a2, a3.
    Alors tous les courriers arrivent à A, a1, à2, à3 ==>seront visibles par la personne X.

    Voici le schéma de l'application :

    #users (id,name,...)
    #destinations (id,name_fr,...)
    #user_has_destinations(user_id,destination_id)
    #courriers(id,titre,description,remarque,...)
    #courriers_has_destinations(courrier_id, destination_id)

    1-J'ai commencé par afficher la liste des courriers de chaque personne (Direction)

    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    select users.id,users.name, 
    group_concat( DISTINCT destinations.name_fr) 
    as directions
    FROM user_has_destinations
    LEFT JOIN users ON user_has_destinations.user_id=users.id
    LEFT JOIN destinations ON user_has_destinations.destination_id=
    destinations.id
    GROUP BY users.id


    2 -Le nombre total et le nombre de courriers (traitées/non traitées) pour chaque direction.


    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    SELECT  users.id,users.name, 
            group_concat( DISTINCT destinations.name_fr) 
            as direction,direction_name,
            COUNT(courriers.remarque) as total,
            COUNT( CASE WHEN courriers.remarque = 1 THEN 1 END ) AS traités,
            COUNT( CASE WHEN courriers.remarque = 0 THEN 1 END ) AS non_traités
            FROM user_has_destinations
            LEFT JOIN users ON user_has_destinations.user_id=users.id
            LEFT JOIN destinations ON user_has_destinations.destination_id=destinations.id
            LEFT JOIN courrier_destination ON user_has_destinations.destination_id=courrier_destination.destination_id
            LEFT JOIN courriers ON courrier_destination.courrier_id=courriers.id
            WHERE users.id IS NOT Null
            GROUP BY users.id

    La deuxième requête est-elle optimale ??


    L'application finale est une application laravel avec un panneau d'administration pour chaque Direction...

    Merci.

  2. #2
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 651
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 651
    Points : 19 925
    Points
    19 925
    Par défaut
    Salut younes2727.

    Vous utilisez MySql 8.0. Je ne sais pas si vous le savez, mais les caches ne sont plus utilisez dans cette version.

    Pour tester la performance de vos requêtes, vous devez utiliser :

    a) le "explain" qui permet de connaitre le plan d'exécution de la requête.
    En fonction des résultats, vous saurez si vous avez besoin de faire l'usage d'un index ou pas, ou encore de le forcer.

    Il suffit de mettre le mot "explain" juste devant votre requête "select".

    b) pour savoir si la modification que vous venez de faire est performante ou pas, vous devez vérifier son temps d'exécution.
    Vous faites :
    Code mysql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    FLUSH TABLE `test`;
    set profiling=1;
    <<votre requête>>
    set profiling=0;
    show profiles;

    Citation Envoyé par younes2727
    La deuxième requête est-elle optimale ??
    On ne peut pas répondre ainsi car cela dépend :
    --> des index.
    --> de la volumétrie.
    --> de la cardinalité de vos valeurs, entre autre de la colonne remarque.
    --> si vos tables sont partitionnées ou pas.
    --> de la charge de votre serveur.
    --> de votre fichier de configuration "my.ini".

    Pourquoi n'utilisez vous pas les alias ?
    Cela permettrait d'alléger votre requête.

    Vous pouvez améliorer vos comptages :
    Code mysql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    left outer join  (  select id,
                               sum(case when remarque = 1 then 1 else 0 end) as Traités,
                               sum(case when remarque = 0 then 1 else 0 end) as Non_Traités,
                               count(remarque)                               as Total
                          from courriers
                     ) as e
                 on  e.id = d.courrier_id
    --> alias d = courrier_destination.

    Cordialement.
    Artemus24.
    @+

  3. #3
    Expert éminent
    Avatar de Séb.
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    5 281
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France

    Informations professionnelles :
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mars 2005
    Messages : 5 281
    Points : 8 589
    Points
    8 589
    Billets dans le blog
    17
    Par défaut
    Le résultat de la requête 2 est bon ? Tu n'as pas des chiffres plus élevés que l'attendu ?
    Il faudrait un échantillon de données

    Au niveau sémantique, pour le décompte tu fais :

    COUNT( CASE WHEN courriers.remarque = 1 THEN 1 END ) AS traités,

    Alors que COUNT() ne compte pas les "1" mais les "IS NOT NULL", ainsi tu pourrais faire :

    COUNT(CASE WHEN courriers.remarque = 1 THEN TRUE END) AS traités,

  4. #4
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 651
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 651
    Points : 19 925
    Points
    19 925
    Par défaut
    Salut Seb.

    C'est pourquoi, je n'ai pas utilisé count() mais sum().

    Cordialement.
    Artemus24.
    @+

Discussions similaires

  1. Réponses: 17
    Dernier message: 27/11/2019, 19h33
  2. Aide pour optimisation d'une requête
    Par yoyodemars dans le forum Développement
    Réponses: 13
    Dernier message: 09/11/2012, 12h59
  3. Demande d'aide pour l'optimisation d'une requête
    Par Menoto dans le forum Optimisations
    Réponses: 4
    Dernier message: 04/04/2008, 13h36
  4. optimisation d'une requête avec jointure
    Par champijulie dans le forum PostgreSQL
    Réponses: 8
    Dernier message: 07/07/2005, 10h45
  5. [DB2] Optimisation d'une requête
    Par ahoyeau dans le forum DB2
    Réponses: 7
    Dernier message: 11/03/2005, 18h54

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