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

SQL Oracle Discussion :

Remplacer une union par une jointure [11g]


Sujet :

SQL Oracle

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éprouvé
    Homme Profil pro
    Analyse système
    Inscrit en
    Juin 2013
    Messages
    976
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Analyse système
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Juin 2013
    Messages : 976
    Par défaut Remplacer une union par une jointure
    Bonjour,

    je me posais une question, j'ai une grosse requête, dans lequel je fais une union et un in et j'ai constaté, après plusieurs recherche sur le net, que l'on pouvais faire une jointure à la place d'une union et que c'était mieux niveau optimisation, seulement j'ai un peu de mal à le faire, voici ceux à quoi ressemble 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
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
     
    (
    select nom,
    prenom,
    identifiant,
    matricule,
    nomsociete,
    date_debut_contrat,
    date_fin_contrat,
    date_reglement
    from table1
    inner join table2...
    inner join table3
    inner join table 4
    .....
    where matricule='0123456'
    and date_fin_contrat >= to_date('2016/12/31 23:59:59','yyyy/mm/dd hh24:mi:ss')
    and date_reglement >= to_date('2016/01/01 00:00:00','yyyy/mm/dd hh24:mi:ss')
    and date_reglement <= to_date('2016/12/31 23:59:59','yyyy/mm/dd hh24:mi:ss')
    and date_reglement <= date_fin_contrat
     
    )
    union
    (
    select nom,
    prenom,
    identifiant,
    nomsociete,
    date_debut_contrat,
    date_fin_contrat,
    date_reglement
    from table1
    inner join table2...
    inner join table3
    inner join table 4
    .....
     
    WHERE  date_reglement >= to_date('2016/01/01 00:00:00','yyyy/mm/dd hh24:mi:ss')
    and date_reglement <= to_date('2016/12/31 23:59:59','yyyy/mm/dd hh24:mi:ss')
    and date_reglement <= date_fin_contrat
    AND date_fin_contrat <> to_date('2999/12/31','yyyy/mm/dd') -- SANS DATE DE FIN 
     
    and identifiant in (
     
    	select 
    	identifiant
    	from table1
    	inner join table2...
    	inner join table3
    	inner join table 4
    	.....
     
    	where matricule='0123456'
    	and date_reglement >= to_date('2016/01/01 00:00:00','yyyy/mm/dd hh24:mi:ss')
    	and date_reglement <= to_date('2016/12/31 23:59:59','yyyy/mm/dd hh24:mi:ss')
    	and date_reglement <= date_fin_contrat
     
    	)
    )
    En gros, je me demandais et je pense que oui à tout hasard, si je peux optimisé ce genre de requête , pour évité l'union et le In?

    merci à vous

  2. #2
    McM
    McM est déconnecté
    Expert confirmé

    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Juillet 2003
    Messages
    4 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Juillet 2003
    Messages : 4 580
    Billets dans le blog
    4
    Par défaut
    Première chose : Attention avec les UNION.
    UNION fait un distinct des lignes (donc gourmand en Tri et en CPU) , donc il faut s'assurer qu'il est nécessaire. Sinon utiliser UNION ALL (qui ne fait pas de distinct et sera donc plus rapide)

    Seconde chose : Mieux vaut éviter le IN et préférer plutôt le EXISTS

    Et enfin, c'est compliquer pour nous d'optimiser une requête sans connaitre le modèle de données et le résultat attendu.
    Mais entre un UNION de 2 requêtes rapides et une Jointure, je pense que je préfère l'UNION (mais ça dépend de la requête)

  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 998
    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 998
    Billets dans le blog
    6
    Par défaut
    Il n'est jamais sûr que l'UNION soit moins optimal qu'une jointure. Ce genre de racontar, y compris avec une pauvre preuve sur un jeu de données bidon, n'a rien à voir avec ce que vous aurez en production.

    UNION (par rapport à une jointure) permet de séparer une grosse requête en deux plus petites et compte tenu des règles de fonctionnement d'un optimiseur, et notamment de la nécessaire corrélation des statistiques, a plus de chance d'obtenir un bon plan que la même requête en jointure, en particulier lorsque la jointure est complexe (nombreuses tables) et qu'il y a de nombreuses opérations de restriction (clause WHERE).

    En conclusion, il faut tester !

    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
    Expert confirmé
    Profil pro
    Inscrit en
    Août 2008
    Messages
    2 953
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 2 953
    Par défaut
    Pas facile d'analyser une requête avec des table1,2,3...

    Je ne vois pas trop l'intérêt du IN, le filtre sur le matricule devrait pouvoir être remonté dans le 2eme SELECT.

    Dans la requête 1 on ne prend que les DATE_FIN_CONTRAT à partir de 2017
    Dans la requête 2, on prend les DATE_FIN_CONTRAT à partir de 2016, mais pas ceux sans date de fin (mais qui sont remontés dans la requête 1)
    Donc je ne vois pas trop l'intérêt de l'UNION non plus, on dirait que la requête pourrait être simplement :
    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
    select nom,
    prenom,
    identifiant,
    matricule,
    nomsociete,
    date_debut_contrat,
    date_fin_contrat,
    date_reglement
    from table1
    inner join table2...
    inner join table3
    inner join table 4
    .....
    where matricule='0123456'
    and date_reglement >= to_date('2016/01/01 00:00:00','yyyy/mm/dd hh24:mi:ss')
    and date_reglement <= to_date('2016/12/31 23:59:59','yyyy/mm/dd hh24:mi:ss')
    and date_reglement <= date_fin_contrat
    A voir si la requête n'a pas été trop simplifiée, ou si je suis passé à côté de quelque chose.

  5. #5
    McM
    McM est déconnecté
    Expert confirmé

    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Juillet 2003
    Messages
    4 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Juillet 2003
    Messages : 4 580
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par skuatamad Voir le message
    Je ne vois pas trop l'intérêt du IN, le filtre sur le matricule devrait pouvoir être remonté dans le 2eme SELECT.
    Comment peux-tu affirmer ça ? Tu ne sais pas quel rôle a IDENTIFIANT. C'est peut être un identifiant qui regrouperait plusieurs matricules.
    C'est pour ça que j'ai dit "compliquer pour nous d'optimiser une requête sans connaitre le modèle de données et le résultat attendu." avec une faute sur "compliqué" d'ailleurs


    PS : Si le but est d'avoir tous les règlements d'une année, moi je préfère utiliser un Extract(year from date_reglement) = 2016 qu'un between entre le 1er janvier et le 31 décembre

  6. #6
    Rédacteur/Modérateur

    Homme Profil pro
    Ingénieur qualité méthodes
    Inscrit en
    Décembre 2013
    Messages
    4 216
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur qualité méthodes
    Secteur : Conseil

    Informations forums :
    Inscription : Décembre 2013
    Messages : 4 216
    Par défaut
    Imzginons que ta requête soit en fait la meilleure solution. Hypothèse d'école. Trop galère pour le diagnostiquer en l'état.

    Je te conseille cependant de la modifier un tout petit peu ; ça ne changera strictement rien en terme de performance, mais ça rendra ta requête plus lisible par un humain. Pourcela, il faut utiliser des alias :
    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
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
     
     
    (
    select t1.nom,
    t1.prenom,
    t1.identifiant,
    t1.matricule,
    t1.nomsociete,
    t1.date_debut_contrat,
    t2.date_fin_contrat,
    t3.date_reglement
    from table1 t2
    inner join table2  t2 
    inner join table3 t3
    inner join table4 t4
    .....
    where t1.matricule='0123456'
    and t2.date_fin_contrat >= to_date('2016/12/31 23:59:59','yyyy/mm/dd hh24:mi:ss')
    and t3.date_reglement >= to_date('2016/01/01 00:00:00','yyyy/mm/dd hh24:mi:ss')
    and t3.date_reglement <= to_date('2016/12/31 23:59:59','yyyy/mm/dd hh24:mi:ss')
    and t3.date_reglement <= t2.date_fin_contrat
     
    )
    union
    (
    select t1.nom,
    t1.prenom,
    t1.identifiant,
    t1.matricule,
    t1.nomsociete,
    t1.date_debut_contrat,
    t2.date_fin_contrat,
    t3.date_reglement
    from table1 t1
    inner join table2 t2
    inner join table3 t3
    inner join table4 t4
    .....
     
    WHERE  t3.date_reglement >= to_date('2016/01/01 00:00:00','yyyy/mm/dd hh24:mi:ss')
    and t3.date_reglement <= to_date('2016/12/31 23:59:59','yyyy/mm/dd hh24:mi:ss')
    and t3.date_reglement <= date_fin_contrat
    AND t2.date_fin_contrat <> to_date('2999/12/31','yyyy/mm/dd') -- SANS DATE DE FIN 
     
    and t1.identifiant in (
     
    	select 
    	t01.identifiant
    	from table1 t01
    	inner join table2 t02
    	inner join table3 t03
    	inner join table4 t04
    	.....
     
    	where t01.matricule='0123456'
    	and t03.date_reglement >= to_date('2016/01/01 00:00:00','yyyy/mm/dd hh24:mi:ss')
    	and t03.date_reglement <= to_date('2016/12/31 23:59:59','yyyy/mm/dd hh24:mi:ss')
    	and t03.date_reglement <= t02.date_fin_contrat
     
    	)
    )
    Si tu dois relire cette requête dans 3 mois, tu seras très content d'avoir rendu ta requête un peu plus lisible.
    Et si tu veux obtenir de l'aide sur ce forum par exemple, c'est indispensable de rendre ta requête compréhensible.

  7. #7
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 998
    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 998
    Billets dans le blog
    6
    Par défaut
    Citation Envoyé par McM Voir le message
    PS : Si le but est d'avoir tous les règlements d'une année, moi je préfère utiliser un Extract(year from date_reglement) = 2016 qu'un between entre le 1er janvier et le 31 décembre
    ATTENTION : tout dépend du moteur SQL… À nouveau certains algébriseurs transformeront le EXTRACT(YEAR...) en BETWEEN afin de rendre la requête "sargable" (à me lire). D'autres pas ! Dans ce dernier cas aucun index ne pourra être utilisé !

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

  8. #8
    Membre éprouvé
    Homme Profil pro
    Analyse système
    Inscrit en
    Juin 2013
    Messages
    976
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Analyse système
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Juin 2013
    Messages : 976
    Par défaut
    Citation Envoyé par McM Voir le message
    Première chose : Attention avec les UNION.
    UNION fait un distinct des lignes (donc gourmand en Tri et en CPU) , donc il faut s'assurer qu'il est nécessaire. Sinon utiliser UNION ALL (qui ne fait pas de distinct et sera donc plus rapide)

    Seconde chose : Mieux vaut éviter le IN et préférer plutôt le EXISTS

    Et enfin, c'est compliquer pour nous d'optimiser une requête sans connaitre le modèle de données et le résultat attendu.
    Mais entre un UNION de 2 requêtes rapides et une Jointure, je pense que je préfère l'UNION (mais ça dépend de la requête)
    Bonjour,
    j'imagine, toutefois ne pourriez vous pas utilisez le modèle de code ci joint ( en utilisant table 1 et table 2 etc ..) ? Car je ne sais pas si ça vient de moi, mais je trouve un peu lourd de faire une union alors que les requêtes sont exactement les même, sauf que dans l'autre il y a une ou deux condition qui diffère, vous voyez où je veux en venir ?

    Il n'est jamais sûr que l'UNION soit moins optimal qu'une jointure. Ce genre de racontar, y compris avec une pauvre preuve sur un jeu de données bidon, n'a rien à voir avec ce que vous aurez en production.

    UNION (par rapport à une jointure) permet de séparer une grosse requête en deux plus petites et compte tenu des règles de fonctionnement d'un optimiseur, et notamment de la nécessaire corrélation des statistiques, a plus de chance d'obtenir un bon plan que la même requête en jointure, en particulier lorsque la jointure est complexe (nombreuses tables) et qu'il y a de nombreuses opérations de restriction (clause WHERE).

    En conclusion, il faut tester !
    Et je me demandais, en matière de temps d'éxecution de la requête sous sqldeveloper,( car au final c'est mon objectif c'est d'optimiser de grosse requête pour un temps d'execution moins long, si possible) est ce mieux que de préféré une union pour des grosses requêtes que des jointures ?

    J'ai lu également par exemple qu'il fallait préféré les between plutot que de prendre une tranche de date ( par ex t1.date>to_date(....) and t1.date<=to_date(....) ou ça ne change rien au final ?
    Merci

  9. #9
    Expert confirmé
    Profil pro
    Inscrit en
    Août 2008
    Messages
    2 953
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 2 953
    Par défaut
    Citation Envoyé par android59 Voir le message
    Car je ne sais pas si ça vient de moi, mais je trouve un peu lourd de faire une union alors que les requêtes sont exactement les même, sauf que dans l'autre il y a une ou deux condition qui diffère
    Pour ce point vous pouvez utiliser une Common Table Expression avec le mot clé WITH, pour factoriser du code au sein de la requête :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    with t as (
    select 1 as c from dual
    )
    select c from t
    union all
    select c from t
    Citation Envoyé par android59 Voir le message
    J'ai lu également par exemple qu'il fallait préféré les between plutot que de prendre une tranche de date ( par ex t1.date>to_date(....) and t1.date<=to_date(....) ou ça ne change rien au final ?
    Ça ne change rien, c'est n'importe quoi.

  10. #10
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 998
    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 998
    Billets dans le blog
    6
    Par défaut
    Citation Envoyé par android59 Voir le message
    J'ai lu également par exemple qu'il fallait préféré les between plutot que de prendre une tranche de date ( par ex t1.date>to_date(....) and t1.date<=to_date(....) ou ça ne change rien au final ?
    Merci
    Vous avez sans doute lu les racontars d'un crétin. BETWEEN ou > AND < est strictement équivalent. La plupart des SGBDR remplacent BETWEEN par des > AND < au niveau de l'algébriseur afin de faciliter la vie de l'optimiseur.

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

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

Discussions similaires

  1. [XL-2007] [FORM] remplacer la valeur d'une cellule par une autre
    Par coldavires dans le forum Excel
    Réponses: 7
    Dernier message: 21/01/2010, 22h34
  2. Remplacer une lettre par une autre dans une cellule
    Par Philippe76 dans le forum Excel
    Réponses: 1
    Dernier message: 09/01/2010, 21h26
  3. [PROC] Remplacer un point par une virgule dans une Proc Tabulate
    Par PAULOM dans le forum SAS Base
    Réponses: 2
    Dernier message: 20/08/2009, 08h36
  4. [Toutes versions] Remplacer "#N/A" par une valeur par défaut
    Par canary dans le forum Macros et VBA Excel
    Réponses: 4
    Dernier message: 10/05/2009, 11h23
  5. [RegEx] Remplacer dernière occurence d'une chaine par une autre
    Par webjoujou dans le forum Langage
    Réponses: 3
    Dernier message: 12/11/2008, 17h58

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