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 d'une requête complexe


Sujet :

Langage SQL

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    24
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 24
    Points : 20
    Points
    20
    Par défaut Optimisation d'une requête complexe
    Bonjour,

    Dans ma base access, j'ai une requête dont l'exécution est particulièrement longue:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT DT.Numéro_dt, DT.Problème_signalé, DT.Nom_opérateur_prob, DT.Problème_signalé, DT.Date_prob, Organe.Organe, Machine.Machine, Section.Section, Organe.Numero_organe
    FROM ([Section] INNER JOIN (Machine INNER JOIN Organe ON Machine.Machine = Organe.Machine) ON Section.Section = Machine.Section) INNER JOIN DT ON Organe.Numero_organe = DT.Num_org
    GROUP BY DT.Numéro_dt, DT.Problème_signalé, DT.Nom_opérateur_prob, DT.Problème_signalé, DT.Date_prob, Organe.Organe, Machine.Machine, Section.Section, Organe.Numero_organe
    HAVING (((DT.Numéro_dt) In (SELECT [Action].[Num_DT] FROM [Action] WHERE Action.Num_DT NOT IN (SELECT Action.Num_DT FROM [Action] WHERE [Action].[Etat]<>"Terminé" GROUP BY Action.Num_DT) GROUP BY [Action].[Num_DT])) AND ((Machine.Machine)=IIf([Tri_machine] Is Not Null,[Tri_machine],[Machine].[Machine])) AND ((Section.Section)=IIf([Tri_section] Is Not Null,[Tri_section],[Section].[Section])) AND ((Organe.Numero_organe)=IIf([Tri_organe] Is Not Null,[Tri_organe],[Organe].[Numero_organe])))
    ORDER BY DT.Numéro_dt DESC;
    Je cherche donc à l'optimiser. Or en y regardant de plus près, il me semble que la partie en gras est superflue. Si je la supprime, la requête devient:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT DT.Numéro_dt, DT.Problème_signalé, DT.Nom_opérateur_prob, DT.Problème_signalé, DT.Date_prob, Organe.Organe, Machine.Machine, Section.Section, Organe.Numero_organe
    FROM ([Section] INNER JOIN (Machine INNER JOIN Organe ON Machine.Machine = Organe.Machine) ON Section.Section = Machine.Section) INNER JOIN DT ON Organe.Numero_organe = DT.Num_org
    GROUP BY DT.Numéro_dt, DT.Problème_signalé, DT.Nom_opérateur_prob, DT.Problème_signalé, DT.Date_prob, Organe.Organe, Machine.Machine, Section.Section, Organe.Numero_organe
    HAVING (((DT.Numéro_dt) Not In (SELECT Action.Num_DT FROM [Action] WHERE [Action].[Etat]<>"Terminé" GROUP BY Action.Num_DT)) AND ((Machine.Machine)=IIf([Tri_machine] Is Not Null,[Tri_machine],[Machine].[Machine])) AND ((Section.Section)=IIf([Tri_section] Is Not Null,[Tri_section],[Section].[Section])) AND ((Organe.Numero_organe)=IIf([Tri_organe] Is Not Null,[Tri_organe],[Organe].[Numero_organe])))
    ORDER BY DT.Numéro_dt DESC;
    Pensez-vous que ce soit équivalent?

    NOTE: Pour info ma base est une MAO (Maintenance Assistée par Ordinateur). Cette requête sert à trier les Demandes de Travail (DT) soldées c'est à dire dont toutes les actions ont été soldées (1 DT = plusieurs actions)

    D'avance merci de votre aide

  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 847
    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 847
    Points : 52 961
    Points
    52 961
    Billets dans le blog
    6
    Par défaut
    Commencez par supprimer toutes les clauses GROUP BY et leur contenu.
    Placez les filtres dans les WHERE. Un GROUP BY n'a d'intérêt que si vous avez des calculs d'agrégats statistiques. Or comme il n'y en a pas cela fait perdre du temps à votre traitement en pure perte.

    Postez à nouveau votre requête en l'identant de manière lisible pour que nous puissions nous pencher dessus à nouveau après cet élagage.

    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/ * * * * *

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    24
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 24
    Points : 20
    Points
    20
    Par défaut
    Voici ce que ça donne après avoir suivi vos conseils.

    Pour l'indentation ce n'est pas forcément très orthodoxe mais ça me semble malgré tout plus lisible...

    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
    SELECT 	DT.Problème_signalé, DT.Nom_opérateur_prob, DT.Problème_signalé, DT.Date_prob, Organe.Organe, Machine.Machine
     
    FROM 	(
    		[Section]
    		INNER JOIN 	(Machine
    				INNER JOIN Organe
    				ON Machine.Machine = Organe.Machine)
    		ON Section.Section = Machine.Section
    	)
    	INNER JOIN DT
    	ON Organe.Numero_organe = DT.Num_org
     
    WHERE 	(
    		((DT.Numéro_dt) NOT IN 	(SELECT Action.Num_DT
    					FROM [Action]
    					WHERE [Action].[Etat]<>"Terminé"
    					GROUP BY Action.Num_DT)
    	)
     	AND ((Machine.Machine)=IIf([Tri_machine] Is Not Null,[Tri_machine],[Machine].[Machine]))
    	AND ((Section.Section)=IIf([Tri_section] Is Not Null,[Tri_section],[Section].[Section]))
    	AND ((Organe.Numero_organe)=IIf([Tri_organe] Is Not Null,[Tri_organe],[Organe].[Numero_organe])))
     
    ORDER BY DT.Numéro_dt DESC;

  4. #4
    Membre chevronné

    Profil pro
    Inscrit en
    Avril 2005
    Messages
    1 673
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2005
    Messages : 1 673
    Points : 1 775
    Points
    1 775
    Par défaut
    Pourquoi mettre certains noms d'objets entre crochets surtout si ce n'est pas systématique ?
    De plus, bon nombre de vos parenthèses sont inutiles.
    Supprimez-les même si ça n'augmentera pas les performances, votre requête n'en sera que plus lisible.
    Voici votre requête épurée :

    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
    SELECT   DT.PROBLèME_SIGNALé,
             DT.NOM_OPéRATEUR_PROB,
             DT.PROBLèME_SIGNALé,
             DT.DATE_PROB,
             ORGANE.ORGANE,
             MACHINE.MACHINE
    FROM     SECTION
             INNER JOIN MACHINE
                        INNER JOIN ORGANE
                          ON MACHINE.MACHINE = ORGANE.MACHINE
               ON SECTION.SECTION = MACHINE.SECTION
             INNER JOIN DT
               ON ORGANE.NUMERO_ORGANE = DT.NUM_ORG
    WHERE    DT.NUMéRO_DT NOT IN (SELECT   ACTION.NUM_DT
                                  FROM     ACTION
                                  WHERE    ACTION.ETAT <> "Terminé"
                                  GROUP BY ACTION.NUM_DT)
             AND MACHINE.MACHINE = IIF(TRI_MACHINE IS NOT NULL,TRI_MACHINE,MACHINE.MACHINE)
             AND SECTION.SECTION = IIF(TRI_SECTION IS NOT NULL,TRI_SECTION,SECTION.SECTION)
             AND ORGANE.NUMERO_ORGANE = IIF(TRI_ORGANE IS NOT NULL,TRI_ORGANE,ORGANE.NUMERO_ORGANE)
    ORDER BY DT.NUMéRO_DT DESC
    Enfin concernant votre question, SQLpro est BIEN plus calé que moi pour vous donner des conseils, néanmoins en analysant le plan de votre requête, voici les points sur lesquels vous pourriez agir :
    - remplacer les [NOT] IN par [NOT] EXISTS
    - remplacer les IIF par des CASE WHEN

    Remarque : je ne suis pas catégorique sur le fait que la suppression des parenthèses que vous avez mis dans la clause FROM ne modifie pas le jeu de résultats obtenu en sorti.
    Cela m'étonnerait mais faîtes-le vous confirmer par un pro
    Modérateur des forums Oracle et Langage SQL
    Forum SQL : je n'interviens PAS plus de 4 fois dans une discussion car si c'est nécessaire cela prouve généralement que vous n'avez pas respecté : les règles du forum

Discussions similaires

  1. Réponses: 4
    Dernier message: 27/08/2009, 10h38
  2. Optimisation d'une requête patchwork
    Par ARRG dans le forum Langage SQL
    Réponses: 1
    Dernier message: 11/09/2005, 15h23
  3. optimisation d'une requête avec jointure
    Par champijulie dans le forum PostgreSQL
    Réponses: 8
    Dernier message: 07/07/2005, 09h45
  4. [DB2] Optimisation d'une requête
    Par ahoyeau dans le forum DB2
    Réponses: 7
    Dernier message: 11/03/2005, 17h54
  5. Encore une requête complexe sur plusieurs tables
    Par DenPro dans le forum Langage SQL
    Réponses: 5
    Dernier message: 09/12/2003, 19h05

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