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 :

"optimiser" une reqûete UNION ALL


Sujet :

Langage SQL

  1. #1
    Membre expert
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 683
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 683
    Points : 3 100
    Points
    3 100
    Par défaut "optimiser" une reqûete UNION ALL
    Bonjour,
    Je viens d'hériter d'une requête que je dois "optimiser" enfin plutôt voire ce qu'on peut faire avec.

    La requête se décompose en deux parties, un peu comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    select champ1, champ2, champ3, champ4
    from table1, table2, table3
    where blabla
    union all
    select champ1, 0 as champ2, champ3, 1 as champ4
    from table1, table2
    where blabla
    Donc vous l'aurez compris l'intérêt (pour moi) du union all est que dans le deuxième select on travaille avec une table en moins et le champ de cette table est remplacé par une constante, parce qu'on en a quand même besoin dans le retour.

    Donc a votre avis est ce que je pourrai faire sauter le union all et un peu raccourcir cette requête? Parce que là ça dépasse un peu mes connaissances de sql.

    Merci de votre aide.
    dam's

  2. #2
    Membre éprouvé
    Profil pro
    Inscrit en
    Août 2008
    Messages
    861
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 861
    Points : 965
    Points
    965
    Par défaut
    Bonjour,

    Sans la vraie requête et une description de ce qu'elle est censée fournir comme infos, il sera difficile de vous aider.
    On parle d'optimisation, donc pourquoi pas la structure et la volumétrie de vos tables, les index, etc...
    Précisez au passage votre SGBD, ça peut aussi servir.

  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 758
    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 758
    Points : 52 535
    Points
    52 535
    Billets dans le blog
    5
    Par défaut
    1 repondez à spinah en respectant les règles de ce forum
    http://www.developpez.net/forums/a69...gage-sql-lire/
    2 transformez le UNION ALL en UNION ci cela est sémantiquement valable

    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
    Membre expert
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 683
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 683
    Points : 3 100
    Points
    3 100
    Par défaut
    Citation Envoyé par Snipah Voir le message
    Bonjour,

    Sans la vraie requête et une description de ce qu'elle est censée fournir comme infos, il sera difficile de vous aider.
    On parle d'optimisation, donc pourquoi pas la structure et la volumétrie de vos tables, les index, etc...
    Précisez au passage votre SGBD, ça peut aussi servir.
    Pour la description de ce que doit faire la requête, je suis un peu dans le flou, on m'a refilé le bébé et débrouilles toi...
    Sinon on est entrain de migrer notre système d'une base DB2 à une base Oracle.
    Je n'ai accès qu'à la dev et une sorte de pré-prod... donc je ne pourrai pas me prononcé sur les index en revanche au niveau de la volumétrie on doit se situer dans les 100.000 lignes.

    Je vais essayer de vous copier la requête en question.
    Merci pour votre aide.
    dam's

  5. #5
    Membre expert
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 683
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 683
    Points : 3 100
    Points
    3 100
    Par défaut
    Voila la fameuse requête

    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
     
    SELECT T3.LIBELLE, T1.NFACTURE AS NUMERO, T2.DATE_PAIEMENT, T1.DATE_DEBUT, T1.DATE_FIN, T2.PUBLIE, T3.TYPE_ABO
    	FROM TABLE1 T1, TABLE2 T2, TABLE3 T3, TABLE4 T4
    		WHERE T1.REFI=T3.REFI 
    		AND T1.NFACTURE=T2.NFACTURE 
    		AND T1.APPLICATION='APPLI' 
    		AND T3.TYPE_ABO=1 
    		AND T2.STATUS_PAIEMENT=0 
    		AND (T4.ID=502 AND T1.USERID=T4.USERID)
    UNION ALL
    SELECT T3.LIBELLE, 0 AS NUMERO, T1.DATE_DEBUT AS DATE_PAIEMENT, T1.DATE_DEBUT, T1.DATE_FIN, 1 AS PUBLIE, T3.TYPE_ABO
    	FROM TABLE1 T1, TABLE3 T3, TABLE4 T4
    		WHERE T1.REFI=T3.REFI 
    		AND T1.APPLICATION='APPLI' 
    		AND (T3.TYPE_ABO=2 OR T3.TYPE_ABO=5) 
    		AND (T4.ID=502 AND T1.USERID=T4.USERID)
    dam's

  6. #6
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 758
    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 758
    Points : 52 535
    Points
    52 535
    Billets dans le blog
    5
    Par défaut
    Optimiser sans savoir quels sont les index et donc ne pas pouvoir en rajouter ne sert strictement à rien. En effet on optimise pas (ou rarement) une requête. On optimise la structure physique des données pour obtenir de meilleures performance sur des requêtes.

    Seule amélioration possible, en supposant qu'il n'y a pas de facture 0 (T1.NFACTURE) : supprimer le ALL de l'UNION.

    Voir cours d'optimisation :
    http://sqlpro.developpez.com/cours/optimiser/
    http://sqlpro.developpez.com/cours/quoi-indexer/
    http://sqlpro.developpez.com/optimisation/

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

  7. #7
    Membre expert
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 683
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 683
    Points : 3 100
    Points
    3 100
    Par défaut
    En fait c'est pas vraiment de l'optimisation (d'où mes guillemets) mais plutôt une amélioration, en fait je crois que cette requête à fait peur et qu'on nous à demandé de la retravailler.

    En tout cas merci pour tes liens, je vais quand même regarder ce que ça donne.
    Et j'ai enlevé aussi le ALL et pour l'instant ça me donne la même chose.

    Merci
    dam's

  8. #8
    Membre éprouvé Avatar de Oishiiii
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Août 2009
    Messages
    508
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Août 2009
    Messages : 508
    Points : 1 104
    Points
    1 104
    Par défaut
    Bonjour,

    J'ai toujours pensé que UNION ALL était plus performant que seulement UNION car (a priori) le SGBD n'a pas le travail supplémentaire de "trier" les lignes pour en supprimer les doublons.

    Citation Envoyé par SQLpro Voir le message
    transformez le UNION ALL en UNION ci cela est sémantiquement valable
    Comment est-ce que cela s'explique ?

  9. #9
    Membre éprouvé
    Profil pro
    Inscrit en
    Août 2008
    Messages
    861
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 861
    Points : 965
    Points
    965
    Par défaut
    J'ai toujours pensé que UNION ALL était plus performant que seulement UNION car (a priori) le SGBD n'a pas le travail supplémentaire de "trier" les lignes pour en supprimer les doublons.
    Idem. Qu'est ce qui justifierait d'enlever le ALL si on n'a pas de doublons?
    Citation Envoyé par dams78 Voir le message
    En fait c'est pas vraiment de l'optimisation (d'où mes guillemets) mais plutôt une amélioration, en fait je crois que cette requête à fait peur et qu'on nous à demandé de la retravailler.
    Vous pouvez toujours la réécrire en utilisant la syntaxe normalisée pour les jointures, peut être qu'elle leur fera moins peur
    Sans connaitre les règles de fonctionnement, ce que représentent vos tables, un éventuel jeu d'essai, etc... on ne pourra pas vraiment vous trouver une requête équivalente.

  10. #10
    Membre expert
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 683
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 683
    Points : 3 100
    Points
    3 100
    Par défaut
    Le problème c'est que je vois pas comment dire de remplacer le numéro de facture dans le deuxième select par la constante 0?
    dam's

  11. #11
    Membre éprouvé
    Profil pro
    Inscrit en
    Août 2008
    Messages
    861
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 861
    Points : 965
    Points
    965
    Par défaut
    Je parlais des jointures, pas du UNION ALL. Votre requête est strictement équivalente à celle ci, 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
     
    SELECT T3.LIBELLE, T1.NFACTURE AS NUMERO, T2.DATE_PAIEMENT, T1.DATE_DEBUT, T1.DATE_FIN, T2.PUBLIE, T3.TYPE_ABO
    FROM TABLE1 T1
    JOIN TABLE2 T2 ON T1.NFACTURE=T2.NFACTURE
    JOIN TABLE3 T3 ON T1.REFI=T3.REFI 
    JOIN TABLE4 T4 ON T1.USERID=T4.USERID
    WHERE T1.APPLICATION='APPLI' 
      AND T3.TYPE_ABO=1 
      AND T2.STATUS_PAIEMENT=0 
      AND T4.ID=502
    UNION ALL
    SELECT T3.LIBELLE, 0 AS NUMERO, T1.DATE_DEBUT AS DATE_PAIEMENT, T1.DATE_DEBUT, T1.DATE_FIN, 1 AS PUBLIE, T3.TYPE_ABO
    FROM TABLE1 T1
    JOIN TABLE3 T3 ON T1.REFI=T3.REFI
    JOIN TABLE4 T4 ON T1.USERID=T4.USERID
    WHERE T1.APPLICATION='APPLI' 
      AND (T3.TYPE_ABO=2 OR T3.TYPE_ABO=5) 
      AND T4.ID=502
    Ensuite, qu'est ce qui justifie de ne pas joindre à la TABLE2 dans la seconde requête?
    Si c'est juste que lorsque T3.TYPE_ABO est égal à 2 ou 5, on n'a pas de correspondance dans T2, alors cette requête avec un LEFT JOIN sur TABLE2 est peut être équivalente :
    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
     
    SELECT T3.LIBELLE, 
           coalesce(T2.NFACTURE,0) AS NUMERO, 
           coalesce(T2.DATE_PAIEMENT,T1.DATE_DEBUT) AS DATE_PAIEMENT, 
           T1.DATE_DEBUT, 
           T1.DATE_FIN, 
           coalesce(T2.PUBLIE,1) AS PUBLIE, 
           T3.TYPE_ABO
    FROM TABLE1 T1
    JOIN TABLE3 T3 ON T1.REFI=T3.REFI
    JOIN TABLE4 T4 ON T1.USERID=T4.USERID
    LEFT JOIN TABLE2 T2 ON T1.NFACTURE=T2.NFACTURE
    WHERE T1.APPLICATION='APPLI' 
      AND T3.TYPE_ABO IN (1,2,5) 
      AND T2.STATUS_PAIEMENT=0 
      AND T4.ID=502
    Si on a des correspondances dans T2 mais qu'on ne veut pas les utiliser lorsque T3.TYPE_ABO est égal à 2 ou 5, alors l'union restera sans doute la solution la plus propre.
    Mais ça on ne peut pas le deviner.

  12. #12
    Membre expert
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 683
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 683
    Points : 3 100
    Points
    3 100
    Par défaut
    J'ai essayé ta requête mais elle me retourne rien, mais je vais continuer à creuser dans ce sens là.
    Par contre pour répondre à ta question il n'y a effectivement pas de tuples dans la table 2 qui correspondent aux retours du deuxième select, en fait la table 2 contient les factures et si le type_abo est à 2 ou 5 il n'y a pas de factures.

    Merci de ton aide
    dam's

  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 758
    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 758
    Points : 52 535
    Points
    52 535
    Billets dans le blog
    5
    Par défaut
    Autant pour moi, j'ai effectivement dit une connerie !!!! Mieux vaut UNION ALL que UNION tout court ! Mea culpa !!!!!


    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
    Membre éprouvé
    Profil pro
    Inscrit en
    Août 2008
    Messages
    861
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 861
    Points : 965
    Points
    965
    Par défaut
    Citation Envoyé par dams78 Voir le message
    J'ai essayé ta requête mais elle me retourne rien, mais je vais continuer à creuser dans ce sens là.
    Par contre pour répondre à ta question il n'y a effectivement pas de tuples dans la table 2 qui correspondent aux retours du deuxième select, en fait la table 2 contient les factures et si le type_abo est à 2 ou 5 il n'y a pas de factures.

    Merci de ton aide
    Oui, j'ai laissé dans la clause WHERE une condition sur une colonne de T2, du coup ça casse la jointure externe.
    Essayez 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
    15
    16
    SELECT T3.LIBELLE, 
           coalesce(T2.NFACTURE,0) AS NUMERO, 
           coalesce(T2.DATE_PAIEMENT,T1.DATE_DEBUT) AS DATE_PAIEMENT, 
           T1.DATE_DEBUT, 
           T1.DATE_FIN, 
           coalesce(T2.PUBLIE,1) AS PUBLIE, 
           T3.TYPE_ABO
    FROM TABLE1 T1
    JOIN TABLE3 T3 ON T1.REFI=T3.REFI
    JOIN TABLE4 T4 ON T1.USERID=T4.USERID
    LEFT JOIN TABLE2 T2 
         ON T1.NFACTURE=T2.NFACTURE
         AND T2.STATUS_PAIEMENT=0 
    WHERE T1.APPLICATION='APPLI' 
      AND T3.TYPE_ABO IN (1,2,5) 
      AND T4.ID=502

  15. #15
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Citation Envoyé par dams78 Voir le message
    J'ai essayé ta requête mais elle me retourne rien, mais je vais continuer à creuser dans ce sens là.
    Par contre pour répondre à ta question il n'y a effectivement pas de tuples dans la table 2 qui correspondent aux retours du deuxième select, en fait la table 2 contient les factures et si le type_abo est à 2 ou 5 il n'y a pas de factures.
    Essaie celle-ci :
    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 T3.LIBELLE, 
           coalesce(T2.NFACTURE,0) AS NUMERO, 
           coalesce(T2.DATE_PAIEMENT,T1.DATE_DEBUT) AS DATE_PAIEMENT, 
           T1.DATE_DEBUT, 
           T1.DATE_FIN, 
           coalesce(T2.PUBLIE,1) AS PUBLIE, 
           T3.TYPE_ABO
    FROM TABLE1 T1
    JOIN TABLE3 T3 ON T1.REFI = T3.REFI
    JOIN TABLE4 T4 ON T1.USERID = T4.USERID
    LEFT JOIN TABLE2 T2 ON T1.NFACTURE = T2.NFACTURE
    WHERE T1.APPLICATION = 'APPLI' 
      AND T4.ID=502
      AND 
      (
        (
          T3.TYPE_ABO = 1
          AND T2.STATUS_PAIEMENT=0
        )
        OR T3.TYPE_ABO IN (2, 5)
      )
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  16. #16
    Membre expert
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 683
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 683
    Points : 3 100
    Points
    3 100
    Par défaut
    Citation Envoyé par CinePhil Voir le message
    Essaie celle-ci :
    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 T3.LIBELLE, 
           coalesce(T2.NFACTURE,0) AS NUMERO, 
           coalesce(T2.DATE_PAIEMENT,T1.DATE_DEBUT) AS DATE_PAIEMENT, 
           T1.DATE_DEBUT, 
           T1.DATE_FIN, 
           coalesce(T2.PUBLIE,1) AS PUBLIE, 
           T3.TYPE_ABO
    FROM TABLE1 T1
    JOIN TABLE3 T3 ON T1.REFI = T3.REFI
    JOIN TABLE4 T4 ON T1.USERID = T4.USERID
    LEFT JOIN TABLE2 T2 ON T1.NFACTURE = T2.NFACTURE
    WHERE T1.APPLICATION = 'APPLI' 
      AND T4.ID=502
      AND 
      (
        (
          T3.TYPE_ABO = 1
          AND T2.STATUS_PAIEMENT=0
        )
        OR T3.TYPE_ABO IN (2, 5)
      )
    Celle-ci fonctionne parfaitement, je vais voire si elle leur convient plus.
    En tout cas merci de votre aide!
    dam's

Discussions similaires

  1. Optimisation d'une requête avec UNION ALL
    Par jgfa9 dans le forum Requêtes
    Réponses: 11
    Dernier message: 01/08/2012, 21h53
  2. Calcul de % sur une requête UNION ALL
    Par lodan dans le forum Langage SQL
    Réponses: 4
    Dernier message: 08/03/2007, 14h20

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