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

 Oracle Discussion :

Jointure : question de syntaxe ou performance


Sujet :

Oracle

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    759
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 759
    Points : 159
    Points
    159
    Par défaut Jointure : question de syntaxe ou performance
    Bonjour,

    Table MA_TABLE (A, Bfk, C, D)
    où Bfk est une colonne que l'on peut jondre la table Tb (FK)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    select t.* from MA_TABLE t
    join Tb on Tb.Bfk = t.Bfk
    where Tb.filtre1 = 2 and Tb.filtre2 = 'V'
    est-il différent de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    select t.* from MA_TABLE t
    join Tb on (Tb.Bfk = t.Bfk and Tb.filtre1 = 2 and Tb.filtre2 = 'V')

    En fait j'essaie aussi d'optimiser cette requête (longue!)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    select *
    from t1
    join t2_v1 on t2_v1.a = t1.a
    join t2_v2 on t2_v2.a = t1.a
    left join t3_v1 on (t3_v1.b = t2_v1.b and t3_v1.filtre1 = 1 and Tb.filtre2 = 'V')
    left join t3_v2 on (t3_v2.b = t2_v2.b and t3_v2.filtre1 = 2 and Tb.filtre2 = 'V')
    ...
    where...
    mais on ne peut pas faire 2 outer join sur la même table donc ça, ça ne marche pas :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    select *
    from t1
    join t2 on t2.a = t1.a
    left join t3_v1 on (t3_v1.b = t2.b and t3_v1.filtre1 = 1 and Tb.filtre2 = 'V')
    left join t3_v2 on (t3_v2.b = t2.b and t3_v2.filtre1 = 2 and Tb.filtre2 = 'V')
    ...
    where...

  2. #2
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Customer Success Manager @Vertica
    Inscrit en
    Septembre 2008
    Messages
    8 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Customer Success Manager @Vertica
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 452
    Points : 17 820
    Points
    17 820
    Par défaut
    Citation Envoyé par stof Voir le message
    Table MA_TABLE (A, Bfk, C, D)
    où Bfk est une jointure vers les la table Tb
    Attention au vocabulaire, c'est important. Une colonne n'est pas une jointure.
    Une jointure n'existe que lors d'une requête, tandis qu'une colonne est persistante.
    Peut-être vouliez-vous parler d'une clef étrangère, ou encore d'une colonne commune ?

    Citation Envoyé par stof Voir le message
    REQUETE1 est-il différent de REQUETE2
    Dans le cas exposé ici, les deux requêtes sont identiques.
    Mais c'est parce que vous l'avez présenté avec une jointure forte (JOIN simple, équivalent à INNER JOIN).
    Avec une jointure externe les requêtes sont différentes.

    Citation Envoyé par stof Voir le message
    En fait j'essaie aussi d'optimiser cette requête (longue!)
    Est-ce que vos tables ou vues t2_v1 / t2_v2 et t3_v1 / t3_v2 sont les mêmes ?
    Dans la clause de jointure avec t3_v2 vous n'y faites pas référence, je pense que c'est une erreur lors de l'écriture de la requête ici.

    Si ce n'est pas confidentiel, n'hésitez pas a publier l'intégralité de votre requête. Si ça l'est, il suffit de changer le nom des objets.

    Citation Envoyé par stof Voir le message
    mais on ne peut pas faire 2 outer join sur la même table donc ça ça ne marche pas
    Je pense que vous vous exprimez mal :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    select t1.dummy as dummy_t1
         , t2.dummy as dummy_t2
         , t3.dummy as dummy_t3
      from dual t1
           left outer join dual t2
             on t2.dummy = t1.dummy
           left outer join dual t3
             on t3.dummy = t1.dummy;
     
    DUMMY_T1 DUMMY_T2 DUMMY_T3
    -------- -------- --------
    X        X        X

  3. #3
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    759
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 759
    Points : 159
    Points
    159
    Par défaut
    J'ai corrigé ma question (oui, t2_v1 / t2_v2 et t3_v1 / t3_v2 désignent une même table t2 et t3).

    Puisque tu veux la requête complète, la voilà mais c'est imbuvable quand on ne connait pas le modèle à mon avis :
    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
    select rownum, t.* 
    from ( 
    select distinct 
    sRef.TITIDT as TITRefIDT, 
    sCpt.TITIDT as TITCptIDT, 
    nvl(( 
    	     select RefREFEXT  
    	     from RefREF aRef 
    	     where aRef.TITIDT = tRef.TITIDT 
    	     and aRef.RefTITIDT = tRef.RefTITIDT 
    	     and aRef.PERTPSDATDEB =(select max(t1.PERTPSDATDEB) from RefREF t1 where t1.PVDIDT != 2 and t1.RefTITIDT = aRef.RefTITIDT and t1.PERTPSDATDEB <= R.DATVL) 
       ), nvl(tRef.RefCOD2,ptRef.PVDTITCOD)) as CODRef, 
    ptCpt.PVDTITCOD as CODCpt, 
    ptRef.PVDTITLIB as LIBRef, 
    ptCpt.PVDTITLIB as LIBCpt, 
    r.DATVL, 
    crsRef.CRSVLO as CRSRef, 
    crsCpt.CRSVLO as CRSCpt, 
    sRef.PLACOTCOD as PLACOTRef, 
    sCpt.PLACOTCOD as PLACOTCpt 
    from RPM r 
    join LIGRPM lr on lr.RPMIDT = r.RPMIDT 
    left join LIGRPMINVLIG lrlRef on lrlRef.LIGRPMIDT = lr.LIGRPMIDT 
    left join LIGRPMINVLIG lrlCpt on lrlCpt.LIGRPMIDT = lr.LIGRPMIDT 
    left join INVLIG ilRef on (ilRef.INVLIGIDT = lrlRef.INVLIGIDT and ilRef.PVDIDT = 2 and ilRef.FLGLIQ = 'F') 
    left join INVLIG ilCpt on (ilCpt.INVLIGIDT = lrlCpt.INVLIGIDT and ilCpt.PVDIDT = r.PVD_PVDIDT and ilCpt.FLGLIQ = 'F') 
    left join STK sRef on sRef.INVLIGIDT = ilRef.INVLIGIDT 
    left join STK sCpt on sCpt.INVLIGIDT = ilCpt.INVLIGIDT 
    left join PVDTIT ptRef on (ptRef.TITIDT = sRef.TITIDT and ptRef.PVDIDT = ilRef.PVDIDT) 
    left join PVDTIT ptCpt on (ptCpt.TITIDT = sCpt.TITIDT and ptCpt.PVDIDT = ilCpt.PVDIDT) 
    left join RefTIT tRef on (tRef.TITIDT = sRef.TITIDT and tRef.STALIGIDT in (select STALIGIDT from STALIG where PVDIDT = r.PVD_PVDIDT and STALIGCOD = case when sRef.QTETIT > 0 then 'RECU' else 'VERSE' end))
    left join CRS crsRef on crsRef.CRSIDT = sRef.CRSIDT 
    left join CRS crsCpt on crsCpt.CRSIDT = sCpt.CRSIDT 
    where r.DATVL = to_date('26/12/2011', 'DD/MM/YYYY')
    and (ptRef.PVDTITCOD is null or ptRef.PVDTITCOD = (select max(PVDTITCOD) from PVDTIT t1 where t1.PVDIDT = 2 and t1.TITIDT = ptRef.TITIDT)) 
    and (ptCpt.PVDTITCOD is null or ptCpt.PVDTITCOD = (select max(PVDTITCOD) from PVDTIT t2 where t2.PVDIDT != 2 and t2.TITIDT = ptCpt.TITIDT)) 
    and (crsRef.CRSVLO is not null or crsCpt.CRSVLO is not null) 
    order by ptRef.PVDTITLIB asc 
    ) t

  4. #4
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Customer Success Manager @Vertica
    Inscrit en
    Septembre 2008
    Messages
    8 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Customer Success Manager @Vertica
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 452
    Points : 17 820
    Points
    17 820
    Par défaut
    Est-ce que la requête ci-dessous est équivalente en terme de résultat ?
    J'ai remplacé certaines sous-requêtes par des jointures.
    Quels sont exactement vos problèmes de performance (volumétries, temps de réponses, explain plan) ?
    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
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    With PVDTIT_AGG AS
    (
      SELECT TITIDT
           , MAX(CASE WHEN PVDIDT  = 2 THEN PVDTITCOD END) AS PVDTITCOD_EQ_2
           , MAX(CASE WHEN PVDIDT <> 2 THEN PVDTITCOD END) AS PVDTITCOD_DF_2
        FROM PVDTIT
    GROUP BY TITIDT
    )
      SELECT DISTINCT 
             sRef.TITIDT AS TITRefIDT
           , sCpt.TITIDT AS TITCptIDT
           , coalesce(aRef.RefREFEXT, tRef.RefCOD2, ptRef.PVDTITCOD) AS CODRef
           , ptCpt.PVDTITCOD AS CODCpt
           , ptRef.PVDTITLIB AS LIBRef
           , ptCpt.PVDTITLIB AS LIBCpt
           , r.DATVL
           , crsRef.CRSVLO   AS CRSRef
           , crsCpt.CRSVLO   AS CRSCpt
           , sRef.PLACOTCOD  AS PLACOTRef
           , sCpt.PLACOTCOD  AS PLACOTCpt 
        FROM RPM r
             INNER JOIN LIGRPM lr
               ON lr.RPMIDT = r.RPMIDT
             LEFT OUTER JOIN LIGRPMINVLIG lrl
               ON lrl.LIGRPMIDT = lr.LIGRPMIDT
             LEFT OUTER JOIN INVLIG ilRef
               ON ilRef.INVLIGIDT = lrl.INVLIGIDT
              AND ilRef.PVDIDT = 2
              AND ilRef.FLGLIQ = 'F'
             LEFT OUTER JOIN STK sRef
               ON sRef.INVLIGIDT = ilRef.INVLIGIDT
             LEFT OUTER JOIN PVDTIT_AGG ptaRef
               ON ptaRef.TITIDT = = sRef.TITIDT
             LEFT OUTER JOIN PVDTIT ptRef
               ON ptRef.TITIDT = ptaRef.TITIDT
              AND ptRef.PVDIDT = 2
              AND ptRef.PVDTITCOD = ptaRef.PVDTITCOD_EQ_2
             LEFT OUTER JOIN RefTIT tRef
               ON tRef.TITIDT = sRef.TITIDT
              AND tRef.STALIGIDT IN (SELECT st.STALIGIDT
                                       FROM STALIG st
                                      WHERE st.PVDIDT = r.PVD_PVDIDT
                                        AND st.STALIGCOD = case when sRef.QTETIT > 0 then 'RECU' else 'VERSE' end)
             LEFT OUTER JOIN RefREF aRef
               ON aRef.TITIDT    = tRef.TITIDT 
              AND aRef.RefTITIDT = tRef.RefTITIDT
              AND aRef.PERTPSDATDEB = (SELECT max(t1.PERTPSDATDEB)
                                         FROM RefREF t1
                                        WHERE t1.PVDIDT <> 2
                                          AND t1.RefTITIDT = aRef.RefTITIDT
                                          AND t1.PERTPSDATDEB <= R.DATVL)
             LEFT OUTER JOIN CRS crsRef
               ON crsRef.CRSIDT = sRef.CRSIDT
             LEFT OUTER JOIN INVLIG ilCpt
               ON ilCpt.INVLIGIDT = lrl.INVLIGIDT
              AND ilCpt.PVDIDT = r.PVD_PVDIDT
              AND ilCpt.FLGLIQ = 'F'
             LEFT OUTER JOIN STK sCpt
               ON sCpt.INVLIGIDT = ilCpt.INVLIGIDT
             LEFT OUTER JOIN PVDTIT_AGG ptasCpt
               ON ptasCpt.TITIDT = = sCpt.TITIDT
             LEFT OUTER JOIN PVDTIT ptCpt
               ON ptCpt.TITIDT = ptasCpt.TITIDT
              AND ptCpt.PVDIDT = ilCpt.PVDIDT
              AND ptCpt.PVDTITCOD = ptasCpt.PVDTITCOD_DF_2
             LEFT OUTER JOIN CRS crsCpt
               ON crsCpt.CRSIDT = sCpt.CRSIDT
       WHERE r.DATVL = to_date('26/12/2011', 'DD/MM/YYYY')
         AND (crsRef.CRSVLO IS NOT NULL
          OR  crsCpt.CRSVLO IS NOT NULL) 
    ORDER BY ptRef.PVDTITLIB ASC;

  5. #5
    Membre expérimenté

    Homme Profil pro
    Inscrit en
    Mars 2010
    Messages
    536
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 536
    Points : 1 359
    Points
    1 359
    Par défaut
    Fabien,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    FROM RPM r
             INNER JOIN LIGRPM lr
               ON lr.RPMIDT = r.RPMIDT
             LEFT OUTER JOIN LIGRPMINVLIG lrl
               ON lrl.LIGRPMIDT = lr.LIGRPMIDT
             LEFT OUTER JOIN INVLIG ilRef
               ON ilRef.INVLIGIDT = lrl.INVLIGIDT
              AND ilRef.PVDIDT = 2
              AND ilRef.FLGLIQ = 'F'
    Pouvez-vous m'expliquer l'intérêt de la jointure externe sur INVLIG ilRef lorsque vous la suivez de

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
              AND ilRef.PVDIDT = 2
              AND ilRef.FLGLIQ = 'F'
    Bien Respectueusement
    www.hourim.wordpress.com

    "Ce qui se conçoit bien s'énonce clairement"

  6. #6
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    759
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 759
    Points : 159
    Points
    159
    Par défaut
    Merci pour ta réponse. j'apprendrai au moins dans un premier temps l'existence de "WITH xxx AS".

    Sinon en dehors de la faute de frappe du ==, la requête ne fonctionne pas car tu tombes comme moi un moment sur la limitation qui donne envie de s'arracher les cheveux dans la section :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
             LEFT OUTER JOIN RefREF aRef
               ON aRef.TITIDT    = tRef.TITIDT 
              AND aRef.RefTITIDT = tRef.RefTITIDT
              AND aRef.PERTPSDATDEB = (SELECT max(t1.PERTPSDATDEB)
                                         FROM RefREF t1
                                        WHERE t1.PVDIDT <> 2
                                          AND t1.RefTITIDT = aRef.RefTITIDT
                                          AND t1.PERTPSDATDEB <= R.DATVL)
    ORA-01799: a column may not be outer-joined to a subquery

  7. #7
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Customer Success Manager @Vertica
    Inscrit en
    Septembre 2008
    Messages
    8 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Customer Success Manager @Vertica
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 452
    Points : 17 820
    Points
    17 820
    Par défaut
    Citation Envoyé par Mohamed.Houri Voir le message
    Pouvez-vous m'expliquer l'intérêt de la jointure externe sur INVLIG ilRef lorsque vous la suivez de...
    Bien sûr, les filtres s'ils sont présents au niveau de la jointure conservent le côté externe de celle-ci.
    C'est strictement équivalent à :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
             LEFT OUTER JOIN LIGRPMINVLIG lrl
               ON lrl.LIGRPMIDT = lr.LIGRPMIDT
             LEFT OUTER JOIN (select *
                                from INVLIG 
                               where PVDIDT = 2
                                 AND FLGLIQ = 'F') ilRef
               ON ilRef.INVLIGIDT = lrl.INVLIGIDT
    Stof, j'ai repris votre requête à l'identique, je pensais qu'elle fonctionnait puisque vous parliez d'optimisation.

    Idéalement un petit jeu de données sur les tables impliquées par cette jointure permettra de bien analyser le besoin.

  8. #8
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    759
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 759
    Points : 159
    Points
    159
    Par défaut
    Citation Envoyé par Waldar Voir le message
    Stof, j'ai repris votre requête à l'identique, je pensais qu'elle fonctionnait puisque vous parliez d'optimisation.
    la mienne fonctionne oui
    Mais la tienne introduit une sous-requête interdite alors que moi je l'ai déportée dans le select (compare la mienne et la tienne au niveau de l'utilisation de la table RefREF)

    Sinon je veux bien te donner mon explain plan mais a priori je ne pourrai pas faire celui de ta requête commençant par "WITH" car Oracle me répond ORA-32034: unsupported use of WITH clause

    Sinon nos 2 requêtes durent à peu près la même durée (sans l'histoire de RefREF réintroduite) mais la mienne renvoie 754 lignes (résultat juste fonctionnellement car déjà validé) et la tienne 506 lignes.

    Mais bon, peut-être qu'on ne peux pas l'améliorer : elle tape dans tellement de (grosses) tables que c'est peut-être difficile de faire mieux (et puis pour toi sans avoir accès à une base similaire, c'est dur de m'aider de façon précise).

  9. #9
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Customer Success Manager @Vertica
    Inscrit en
    Septembre 2008
    Messages
    8 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Customer Success Manager @Vertica
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 452
    Points : 17 820
    Points
    17 820
    Par défaut
    J'ai oublié une question essentielle en effet, quelle version d'Oracle ?

    L'explain plan, c'est toujours bon à prendre, mais j'ai surtout besoin de quelques données représentatives pour réécrire en partie votre requête.

    J'imagine très bien que vous cherchez des informations relatives à un dernier statut, mais j'ai besoin de bien me le représenter - et de pouvoir tester.

    Si les deux requêtes ne renvoient pas le même nombre de lignes, c'est que j'ai raté quelque chose, je pensais qu'elles étaient équivalentes.

  10. #10
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    759
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 759
    Points : 159
    Points
    159
    Par défaut
    Citation Envoyé par Waldar Voir le message
    J'ai oublié une question essentielle en effet, quelle version d'Oracle ?
    10.2

    Citation Envoyé par Waldar Voir le message
    j'ai surtout besoin de quelques données représentatives pour réécrire en partie votre requête.
    Je ne vois pas comment on pourrait créer un jeu qui reflète ma base avec toutes ces tables ayant tous ces milliers de lignes

  11. #11
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Customer Success Manager @Vertica
    Inscrit en
    Septembre 2008
    Messages
    8 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Customer Success Manager @Vertica
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 452
    Points : 17 820
    Points
    17 820
    Par défaut
    En partant d'une seule valeur de RPM.RPMIDT, qui n'a pas trop de lignes dans les autres tables, ça doit pouvoir se trouver à coup de count(*).

  12. #12
    Membre expérimenté

    Homme Profil pro
    Inscrit en
    Mars 2010
    Messages
    536
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 536
    Points : 1 359
    Points
    1 359
    Par défaut
    Bien sûr, les filtres s'ils sont présents au niveau de la jointure conservent le côté externe de celle-ci.
    C'est strictement équivalent à :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
             LEFT OUTER JOIN LIGRPMINVLIG lrl
               ON lrl.LIGRPMIDT = lr.LIGRPMIDT
             LEFT OUTER JOIN (select *
                                from INVLIG 
                               where PVDIDT = 2
                                 AND FLGLIQ = 'F') ilRef
               ON ilRef.INVLIGIDT = lrl.INVLIGIDT
    Fabien,

    Une jointure externe sur une table t est inutile à partir du moment où vous la faite suivre d'une clause du type and t.autre_colonne = 'n'importe quelle valeur';

    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
     
    mhouri.world> select
      2       *
      3  from emp
      4  where deptno is null;
     
      EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO               
    ---------- ---------- --------- ---------- --------- ---------- ---------- ----------               
      9999 Anonyme    Oracle          7839 22-APR-11       1500                                     
     
    mhouri.world> select count(1) from emp;
     
      COUNT(1)                                                                                          
    ----------                                                                                          
            15                                                                                          
     
    mhouri.world> select
      2       count(1)
      3  from emp
      4  join dept
      5  on  emp.deptno = dept.deptno
      6  order by emp.deptno
      7  ;
     
      COUNT(1)                                                                                          
    ----------                                                                                          
            14                                                                                          
     
    mhouri.world> select
      2       count(1)
      3  from emp
      4  left outer join dept
      5  on  emp.deptno = dept.deptno
      6  order by emp.deptno
      7  ;
     
      COUNT(1)                                                                                          
    ----------                                                                                          
            15
    Ok ici ça fonctionne la 15ème ligne ayant un département NULL est sélectionnée. Mais observons le cas où une clause supplémentaire est ajoutée à la jointure externe

    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
     
    mhouri.world> select
      2       count(1)
      3  from emp
      4  left outer join dept
      5  on  emp.deptno = dept.deptno
      6  where dept.loc = 'DALLAS'
      7  order by emp.deptno
      8  ;
     
      COUNT(1)                                                                                          
    ----------                                                                                          
             5                                                                                          
     
    mhouri.world> select
      2       count(1)
      3  from emp
      4  join dept
      5  on  emp.deptno = dept.deptno
      6  where dept.loc = 'DALLAS'
      7  order by emp.deptno
      8  ;
     
      COUNT(1)                                                                                          
    ----------                                                                                          
             5
    On voit bien maintenant que les deux types de jointures retournent le même résultat lorsque la clause supplémentaire dept.loc = 'DALLAS' est présente. Car comment voulez-vous que l'on génère une ligne supplémentaire dans dept avec des NULLs et qu'au même moment ces NULLs doivent avoir un dept.loc = 'DALLAS'!!!

    Je passe maintenant aux jointures Oracle

    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
     
    mhouri.world> select
      2       count(1)
      3  from emp
      4      ,dept
      5  where emp.deptno = dept.deptno(+)
      6  and   dept.loc = 'DALLAS'
      7  order by emp.deptno
      8  ;
     
      COUNT(1)                                                                                          
    ----------                                                                                          
             5                                                                                          
     
    mhouri.world> select
      2       count(1)
      3  from emp
      4      ,dept
      5  where emp.deptno = dept.deptno
      6  and   dept.loc = 'DALLAS'
      7  order by emp.deptno
      8  ;
     
      COUNT(1)                                                                                          
    ----------                                                                                          
             5                                                                                          
     
    mhouri.world> select
      2       count(1)
      3  from emp
      4      ,dept
      5  where emp.deptno = dept.deptno(+)
      6  and   dept.loc(+) = 'DALLAS'
      7  order by emp.deptno
      8  ;
     
      COUNT(1)                                                                                          
    ----------                                                                                          
            15
    Voilà qui est légèrement différent car j'ai ajouté une jointure externe à la clause supplémentaire sur dep.loc(+) = 'DALLAS'.

    Enfin, 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
     
    mhouri.world> select
      2       count(1)
      3  from emp
      4  left outer join (select *
      5                   from dept
      6                    where dept.loc = 'DALLAS'
      7                   ) d
      8  on  emp.deptno = d.deptno
      9  ;
     
      COUNT(1)                                                                                          
    ----------                                                                                          
            15
    est correct car il n'y a pas de filtre sur les lignes nulles fabriquées par la jointure externe (le filtre est appliqué avant la jointure
    externe)
    Bien Respectueusement
    www.hourim.wordpress.com

    "Ce qui se conçoit bien s'énonce clairement"

  13. #13
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Customer Success Manager @Vertica
    Inscrit en
    Septembre 2008
    Messages
    8 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Customer Success Manager @Vertica
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 452
    Points : 17 820
    Points
    17 820
    Par défaut
    Mohamed, je suis d'accord avec votre démonstration, mais je ne vois rien de contradictoire entre votre démonstration et mes propos !

    Pour refléter la discussion, il aurait fallu que vous testiez avec cette jointure :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    FROM emp
         LEFT OUTER JOIN dept
           ON dept.deptno = emp.deptno
          AND dept.loc    = 'DALLAS'

  14. #14
    Membre expérimenté

    Homme Profil pro
    Inscrit en
    Mars 2010
    Messages
    536
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 536
    Points : 1 359
    Points
    1 359
    Par défaut
    Citation Envoyé par Waldar Voir le message
    Mohamed, je suis d'accord avec votre démonstration, mais je ne vois rien de contradictoire entre votre démonstration et mes propos !

    Pour refléter la discussion, il aurait fallu que vous testiez avec cette jointure :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    FROM emp
         LEFT OUTER JOIN dept
           ON dept.deptno = emp.deptno
          AND dept.loc    = 'DALLAS'
    Fabien,

    Oui c'est exact et après vérification vous avez tout à fait raison. Désolé
    Bien Respectueusement
    www.hourim.wordpress.com

    "Ce qui se conçoit bien s'énonce clairement"

  15. #15
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    759
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 759
    Points : 159
    Points
    159
    Par défaut
    Bon, je pense que je vais "fermer" le sujet parce que ça me semble difficile de proposer un jeu de test pour ma grosse requête.

    Si Oracle refuse les sous-requêtes dans les jointures (du moins dans ma version d'Oracle), on ne peut peut-être pas faire mieux pour ramener tout ce que j'ai à ramener.

  16. #16
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Customer Success Manager @Vertica
    Inscrit en
    Septembre 2008
    Messages
    8 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Customer Success Manager @Vertica
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 452
    Points : 17 820
    Points
    17 820
    Par défaut
    Je suis persuadé que si ! Regardez comment est construite la requête, on retrouve deux branches distinctes avec quasiment les mêmes tables dedans.

    Le distinct sur ce genre de requête pourrait indiquer soit un problème de modélisation, soit un problème au niveau de l'écriture de la requête.

    En utilisant les techniques de pivot et de fonctions d'agrégat pour retrouver la dernière valeur associée à une date je pense qu'on peut améliorer la requête.

  17. #17
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    759
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 759
    Points : 159
    Points
    159
    Par défaut
    Citation Envoyé par Waldar Voir le message
    Le distinct sur ce genre de requête pourrait indiquer soit un problème de modélisation, soit un problème au niveau de l'écriture de la requête.
    Sans le distinct, 976 résultats contre 754 avec.
    Je regarde cette après-midi ce qui cause cette différence.

    Citation Envoyé par Waldar Voir le message
    En utilisant les techniques de pivot et de fonctions d'agrégat pour retrouver la dernière valeur associée à une date je pense qu'on peut améliorer la requête.
    Où penses-tu qu'il manquerait des aggrégats? C'est quoi les "techniques de pivots" que tu évoques?

  18. #18
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    759
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 759
    Points : 159
    Points
    159
    Par défaut
    Il y a un truc qui ne "va pas" dès le début de la création des 2 branches parallèles :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    SELECT *
    FROM RPM r 
    JOIN LIGRPM lr ON lr.RPMIDT = r.RPMIDT 
    LEFT JOIN LIGRPMINVLIG lrlRef ON lrlRef.LIGRPMIDT = lr.LIGRPMIDT 
    LEFT JOIN LIGRPMINVLIG lrlCpt ON lrlCpt.LIGRPMIDT = lr.LIGRPMIDT
    En fait quand on regarde les données à ce stade, elles ne sont pas jointes dans le même ordre pour lrlRef et lrlCpt; certes on ne les lit pas pour les données renvoyées puisqu'elles ne servent que d'intermédiaire mais elles expliquent pourquoi j'ai du rajouter un distinct.

    Par contre là où je sens peu d'espoir (hors chantier de changement des index sur la base en réflexion en parallèle), c'est que rien que ce bout de requête prend déjà 1/3 du temps de la grosse requête proposée initialement :
    Donc comme il faut aussi aller faire le même genre de chose pour l'autre branche on explique déjà 2/3 du temps sans rien pouvoir faire, le reste étant les recherches annexes...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    select sRef.*
    from RPM r 
    join LIGRPM lr on lr.RPMIDT = r.RPMIDT
    join LIGRPMINVLIG lrlRef on lrlRef.LIGRPMIDT = lr.LIGRPMIDT
    join INVLIG ilRef on (ilRef.INVLIGIDT = lrlRef.INVLIGIDT and ilRef.PVDIDT = 2 and ilRef.FLGLIQ = 'F') 
    join STK sRef on sRef.INVLIGIDT = ilRef.INVLIGIDT 
    where r.DATVL = to_date('26/12/2011', 'DD/MM/YYYY')

  19. #19
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Customer Success Manager @Vertica
    Inscrit en
    Septembre 2008
    Messages
    8 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Customer Success Manager @Vertica
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 452
    Points : 17 820
    Points
    17 820
    Par défaut
    Oui j'avais sucré une de ces deux jointures dans ma requête, compte tenu qu'il s'agit du même prédicat de jointure et qu'à ce stade il n'y a pas encore de différenciation entre les deux branches.

  20. #20
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    759
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 759
    Points : 159
    Points
    159
    Par défaut
    Citation Envoyé par Waldar Voir le message
    Oui j'avais sucré une de ces deux jointures dans ma requête, compte tenu qu'il s'agit du même prédicat de jointure et qu'à ce stade il n'y a pas encore de différenciation entre les deux branches.
    Bah oui, moi aussi ça m'aurait paru logique mais ça ne fonctionne pas pour une raison qui m'échappe encore (les données renvoyées ne sont pas celles attendues avec cette écriture non différenciée à ce niveau).

    PS : j'ai enrichi mon message précédent (cf partie 2)

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Question de syntaxe
    Par dafalri dans le forum VB 6 et antérieur
    Réponses: 12
    Dernier message: 13/12/2005, 20h57
  2. [XML] Questions de syntaxe
    Par ghohm dans le forum XML/XSL et SOAP
    Réponses: 4
    Dernier message: 03/11/2005, 12h08
  3. question sur syntaxe d'une requete
    Par sparis dans le forum MS SQL Server
    Réponses: 8
    Dernier message: 29/09/2005, 11h58
  4. [C linux makefile] question de syntaxe
    Par Ultros dans le forum Systèmes de compilation
    Réponses: 7
    Dernier message: 09/04/2004, 07h58
  5. Réponses: 2
    Dernier message: 08/03/2004, 15h10

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