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 :

Optimisation requête SQL


Sujet :

Langage SQL

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Dev
    Inscrit en
    Octobre 2014
    Messages
    35
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Dev

    Informations forums :
    Inscription : Octobre 2014
    Messages : 35
    Points : 30
    Points
    30
    Par défaut Optimisation requête SQL
    (Re) Bonjour,

    je reviens vers vous pour savoir si il serait possible d'optimiser une de mes requêtes. Celle-ci fonctionne, retourne le résultat voulu, mais j'aimerai savoir si il serait possible de l'améliorer pour booster les perfs.

    Je cherche à obtenir le nombre de clients inscrit chaque mois ainsi que le nombre de clients convertis (ayant passé une commande). Voici ma requête à l'heure actuelle :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    SELECT 
            COUNT( client.id ) AS nbClient, 
    	DATE_FORMAT( client.created, "%Y" ) AS year, 
    	DATE_FORMAT( client.created, "%m" ) AS month, 
    	SUM(
    		CASE WHEN (SELECT COUNT( * ) FROM commande WHERE commande.idClient = client.id ) > 0
    		THEN 1
    		ELSE 0
    		END
    	) AS nbConvertis
    FROM client
    WHERE client.created >= '2015-01-01'
    AND client.created < '2015-09-17'
    GROUP BY DATE_FORMAT( client.created, "%Y-%m" )
    Je pense que la sous-requête prend beaucoup de ressources (sachant que pour l'année 2015, j'ai environ 1000 clients inscrits). Pensez-vous qu'il est possible de l'optimiser ?

    Merci par avance

  2. #2
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 136
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : bourreau
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2010
    Messages : 10 136
    Points : 38 909
    Points
    38 909
    Billets dans le blog
    9
    Par défaut
    Bonjour,

    En effet, votre sous requête ne devrait pas utiliser un select mais faire un test d'existence comme suit
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    WHERE EXISTS SELECT 0 FROM  commande WHERE commande.idClient = client.id

  3. #3
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 770
    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 770
    Points : 52 726
    Points
    52 726
    Billets dans le blog
    5
    Par défaut
    Cette requête est totalement imbécile... je suppose que c'est du MySQmerde ? En effet COUNT(id_client) doit vous renvoyer toujours rien ?
    De plus votre groupage ne correspond pas à votre SELECT....

    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  4. #4
    Nouveau membre du Club
    Homme Profil pro
    Dev
    Inscrit en
    Octobre 2014
    Messages
    35
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Dev

    Informations forums :
    Inscription : Octobre 2014
    Messages : 35
    Points : 30
    Points
    30
    Par défaut
    Bonjour,

    merci à vous deux pour votre aide,

    Citation Envoyé par escartefigue Voir le message
    Bonjour,

    En effet, votre sous requête ne devrait pas utiliser un select mais faire un test d'existence comme suit
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    WHERE EXISTS SELECT 0 FROM  commande WHERE commande.idClient = client.id
    Je ne comprends pas comment intégrer cela à ma requête ? Cela fonctionne avec MySql ?

    Citation Envoyé par SQLpro Voir le message
    Cette requête est totalement imbécile... je suppose que c'est du MySQmerde ? En effet COUNT(id_client) doit vous renvoyer toujours rien ?
    De plus votre groupage ne correspond pas à votre SELECT....

    A +
    Je ne comprend pas votre remarque :/ Oui je suis en MySql (pas le choix du SGBD malheureusement) mais la requête fonctionne parfaitement et les résultats sont justes (validés après une vérification manuelle).

  5. #5
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 136
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : bourreau
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2010
    Messages : 10 136
    Points : 38 909
    Points
    38 909
    Billets dans le blog
    9
    Par défaut
    Essayez comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    SELECT 
            COUNT( client.id ) AS nbClient, 
    	DATE_FORMAT( client.created, "%Y" ) AS year, 
    	DATE_FORMAT( client.created, "%m" ) AS month, 
    	SUM(
    		CASE WHEN EXISTS (SELECT 0 FROM commande WHERE commande.idClient = client.id )
     		THEN 1
    		ELSE 0
    		END
    	) AS nbConvertis
    FROM client
    WHERE client.created >= '2015-01-01'
    GROUP BY 1, 2, 3

  6. #6
    Membre expérimenté
    Homme Profil pro
    Ingenieur de recherche - Ecologue
    Inscrit en
    Juin 2003
    Messages
    1 146
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingenieur de recherche - Ecologue

    Informations forums :
    Inscription : Juin 2003
    Messages : 1 146
    Points : 1 412
    Points
    1 412
    Par défaut
    Bonjour

    Et pourquoi ne pas utiliser une jointure entre les 2 tables ?
    Merci d'ajouter un sur les tags qui vous ont aidé

  7. #7
    Nouveau membre du Club
    Homme Profil pro
    Dev
    Inscrit en
    Octobre 2014
    Messages
    35
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Dev

    Informations forums :
    Inscription : Octobre 2014
    Messages : 35
    Points : 30
    Points
    30
    Par défaut
    Citation Envoyé par escartefigue Voir le message
    Essayez comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    SELECT 
            COUNT( client.id ) AS nbClient, 
    	DATE_FORMAT( client.created, "%Y" ) AS year, 
    	DATE_FORMAT( client.created, "%m" ) AS month, 
    	SUM(
    		CASE WHEN EXISTS (SELECT 0 FROM commande WHERE commande.idClient = client.id )
     		THEN 1
    		ELSE 0
    		END
    	) AS nbConvertis
    FROM client
    WHERE client.created >= '2015-01-01'
    GROUP BY 1, 2, 3
    En effet, cela fonctionne mais j'ai pas l'impression de ressentir des améliorations de performances, toujours 7 secondes pour l'exécution de la requête :/

    Citation Envoyé par dehorter olivier Voir le message
    Bonjour

    Et pourquoi ne pas utiliser une jointure entre les 2 tables ?
    Sachant qu'un client peut avoir potentiellement plusieurs commandes et que je souhaites grouper par dates, je n'arrive pas à avoir comment organiser ma requête autour d'une jointure :/

  8. #8
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 136
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : bourreau
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2010
    Messages : 10 136
    Points : 38 909
    Points
    38 909
    Billets dans le blog
    9
    Par défaut
    Citation Envoyé par devnet75 Voir le message
    En effet, cela fonctionne mais j'ai pas l'impression de ressentir des améliorations de performances, toujours 7 secondes pour l'exécution de la requête :/
    Votre colonne date sur laquelle vous filtrez est elle indexée ? si oui quelle proportion de la population correspond au critère ?
    Avez vous fait un explain de la requête ?

    Concernant la jointure outer pour le test d'existence, elle sera au mieux égale en perf à un where exist, et souvent plus mauvaise (d'autant moins bonne qu'il y aura d'enregistrements en correspondance dans la table outer)
    un where exists est donc le plus souvent préférable

  9. #9
    Membre expérimenté
    Homme Profil pro
    Ingenieur de recherche - Ecologue
    Inscrit en
    Juin 2003
    Messages
    1 146
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingenieur de recherche - Ecologue

    Informations forums :
    Inscription : Juin 2003
    Messages : 1 146
    Points : 1 412
    Points
    1 412
    Par défaut
    par un truc comme cela, à adapter bien entendu
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    SELECT 
            COUNT(DISTINCT client.id ) AS nbClient, 
    	DATE_FORMAT( client.created, "%Y" ) AS year, 
    	DATE_FORMAT( client.created, "%m" ) AS month, 
            COUNT(*)
    FROM client
       INNER JOIN Commande ON Commande.idclient = client.idclient
    WHERE client.created >= '2015-01-01'
    GROUP BY 2, 3
    Merci d'ajouter un sur les tags qui vous ont aidé

  10. #10
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 136
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : bourreau
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2010
    Messages : 10 136
    Points : 38 909
    Points
    38 909
    Billets dans le blog
    9
    Par défaut
    Citation Envoyé par dehorter olivier Voir le message
    par un truc comme cela, à adapter bien entendu
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    SELECT 
            COUNT(DISTINCT client.id ) AS nbClient, 
    	DATE_FORMAT( client.created, "%Y" ) AS year, 
    	DATE_FORMAT( client.created, "%m" ) AS month, 
            COUNT(*)
    FROM client
       INNER JOIN Commande ON Commande.idclient = client.idclient
    WHERE client.created >= '2015-01-01'
    GROUP BY 2, 3
    Sauf que cette solution provoque autant de jointures avec la table des commandes qu'il y a de lignes de commandes pour le client
    Puisqu'on n'a besoin d'aucune colonne de la table commandes, cette solution est à éviter, il faut préférer where exists

  11. #11
    Membre expérimenté
    Homme Profil pro
    Ingenieur de recherche - Ecologue
    Inscrit en
    Juin 2003
    Messages
    1 146
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingenieur de recherche - Ecologue

    Informations forums :
    Inscription : Juin 2003
    Messages : 1 146
    Points : 1 412
    Points
    1 412
    Par défaut
    Certes, mais sous MySql cela ne serait-il pas plus rapide ? je ne sais pas

    Si tant est que les index existent !

    escartefigue, je n'avais pas vu que tu étais "bourreau", ca fait peur
    Merci d'ajouter un sur les tags qui vous ont aidé

  12. #12
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 136
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : bourreau
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2010
    Messages : 10 136
    Points : 38 909
    Points
    38 909
    Billets dans le blog
    9
    Par défaut
    Citation Envoyé par dehorter olivier Voir le message
    Certes, mais sous MySql cela ne serait-il pas plus rapide ? je ne sais pas
    non quelque soit le SGBD

    Citation Envoyé par dehorter olivier Voir le message
    Si tant est que les index existent !
    Certes j'ose espérer que l'index entre les commandes et les clients n'a pas été oublié

    Citation Envoyé par dehorter olivier Voir le message
    escartefigue, je n'avais pas vu que tu étais "bourreau", ca fait peur
    Ce n'est pas mon métier, juste une vocation inassouvie

  13. #13
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 770
    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 770
    Points : 52 726
    Points
    52 726
    Billets dans le blog
    5
    Par défaut
    Sans la description des tables et notamment des types de chaque colonnes et des index de la table, difficile de vous répondre. De plus MySQL ayant l'un des plus mauvais optimiseur, il est parfaitement crédible que le EXISTS n'apporte aucun gain !

    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  14. #14
    Nouveau membre du Club
    Homme Profil pro
    Dev
    Inscrit en
    Octobre 2014
    Messages
    35
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Dev

    Informations forums :
    Inscription : Octobre 2014
    Messages : 35
    Points : 30
    Points
    30
    Par défaut
    Bonjour tout le monde,

    je reviens vers vous pour vous donner les retours de tous mes essais. Voyant que le passage au exists n'avait pas amélioré les performances et suite à la remarque de escartefigue sur les indexs je m'y suis penché d'un peu plus près.

    Du coup, j'ai rajouté un index sur la colonne idClient de la table Commande et ça a tout débloqué ! La requête s'exécute maintenant en quelques dixièmes de seconde.

    Merci à tous pour votre aide

  15. #15
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 136
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : bourreau
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2010
    Messages : 10 136
    Points : 38 909
    Points
    38 909
    Billets dans le blog
    9
    Par défaut
    Maintenant que vous avez les index requis, faites la comparaison enter la jointure inner telle que vous l'aviez construite initialement, et la requête avec exists.
    Il est très probable que vous constaterez un écart significatif en temps CPU, au bénéfice de la requête exists.

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

Discussions similaires

  1. Optimisation requête SQL
    Par ludo00002 dans le forum SQL
    Réponses: 2
    Dernier message: 06/10/2008, 09h01
  2. Comment optimiser requête SQL avec création Index
    Par schumi101 dans le forum SQL
    Réponses: 25
    Dernier message: 11/12/2007, 21h28
  3. optimisation requête SQL
    Par marti dans le forum Oracle
    Réponses: 4
    Dernier message: 27/04/2006, 08h54
  4. Besoin d'aide pour optimiser requête SQL
    Par Keuf95 dans le forum Langage SQL
    Réponses: 10
    Dernier message: 06/09/2005, 16h02
  5. optimisation requête SQL!!! help!!
    Par anathem62 dans le forum Requêtes
    Réponses: 2
    Dernier message: 24/05/2004, 16h26

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