Précédent   Forum des professionnels en informatique > Bases de données > Oracle > Débuter
Débuter Forum d'entraide pour débuter avec Oracle
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 28/12/2011, 10h05   #1
Membre habitué
 
Inscription : décembre 2004
Messages : 643
Détails du profil
Informations forums :
Inscription : décembre 2004
Messages : 643
Points : 104
Points : 104
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 :
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 :
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 :
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 :
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...
stof est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/12/2011, 10h59   #2
Modérateur
 
Homme Fabien
Ingénieur d'études en décisionnel
Inscription : septembre 2008
Messages : 5 686
Détails du profil
Informations personnelles :
Nom : Homme Fabien
Âge : 34
Localisation : France, Yvelines (Île de France)

Informations professionnelles :
Activité : Ingénieur d'études en décisionnel
Secteur : Arts - Culture

Informations forums :
Inscription : septembre 2008
Messages : 5 686
Points : 10 435
Points : 10 435
Envoyer un message via ICQ à Waldar Envoyer un message via Skype™ à Waldar
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 :
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
__________________
Email : http://scr.im/waldar
Waldar est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/12/2011, 11h10   #3
Membre habitué
 
Inscription : décembre 2004
Messages : 643
Détails du profil
Informations forums :
Inscription : décembre 2004
Messages : 643
Points : 104
Points : 104
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 :
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
stof est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/12/2011, 12h11   #4
Modérateur
 
Homme Fabien
Ingénieur d'études en décisionnel
Inscription : septembre 2008
Messages : 5 686
Détails du profil
Informations personnelles :
Nom : Homme Fabien
Âge : 34
Localisation : France, Yvelines (Île de France)

Informations professionnelles :
Activité : Ingénieur d'études en décisionnel
Secteur : Arts - Culture

Informations forums :
Inscription : septembre 2008
Messages : 5 686
Points : 10 435
Points : 10 435
Envoyer un message via ICQ à Waldar Envoyer un message via Skype™ à Waldar
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 :
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;
__________________
Email : http://scr.im/waldar
Waldar est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/12/2011, 13h33   #5
Membre expérimenté
 
Homme Mohamed Houri
Inscription : mars 2010
Messages : 286
Détails du profil
Informations personnelles :
Nom : Homme Mohamed Houri
Localisation : France

Informations forums :
Inscription : mars 2010
Messages : 286
Points : 562
Points : 562
Fabien,

Code :
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 :
1
2
3
 
          AND ilRef.PVDIDT = 2
          AND ilRef.FLGLIQ = 'F'
__________________
Bien Cordialement
www.hourim.wordpress.com
Mohamed.Houri est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/12/2011, 14h11   #6
Membre habitué
 
Inscription : décembre 2004
Messages : 643
Détails du profil
Informations forums :
Inscription : décembre 2004
Messages : 643
Points : 104
Points : 104
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 :
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
stof est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/12/2011, 14h30   #7
Modérateur
 
Homme Fabien
Ingénieur d'études en décisionnel
Inscription : septembre 2008
Messages : 5 686
Détails du profil
Informations personnelles :
Nom : Homme Fabien
Âge : 34
Localisation : France, Yvelines (Île de France)

Informations professionnelles :
Activité : Ingénieur d'études en décisionnel
Secteur : Arts - Culture

Informations forums :
Inscription : septembre 2008
Messages : 5 686
Points : 10 435
Points : 10 435
Envoyer un message via ICQ à Waldar Envoyer un message via Skype™ à Waldar
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 :
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.
__________________
Email : http://scr.im/waldar
Waldar est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/12/2011, 14h42   #8
Membre habitué
 
Inscription : décembre 2004
Messages : 643
Détails du profil
Informations forums :
Inscription : décembre 2004
Messages : 643
Points : 104
Points : 104
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).
stof est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/12/2011, 14h49   #9
Modérateur
 
Homme Fabien
Ingénieur d'études en décisionnel
Inscription : septembre 2008
Messages : 5 686
Détails du profil
Informations personnelles :
Nom : Homme Fabien
Âge : 34
Localisation : France, Yvelines (Île de France)

Informations professionnelles :
Activité : Ingénieur d'études en décisionnel
Secteur : Arts - Culture

Informations forums :
Inscription : septembre 2008
Messages : 5 686
Points : 10 435
Points : 10 435
Envoyer un message via ICQ à Waldar Envoyer un message via Skype™ à Waldar
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.
__________________
Email : http://scr.im/waldar
Waldar est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/12/2011, 15h16   #10
Membre habitué
 
Inscription : décembre 2004
Messages : 643
Détails du profil
Informations forums :
Inscription : décembre 2004
Messages : 643
Points : 104
Points : 104
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
stof est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/12/2011, 15h19   #11
Modérateur
 
Homme Fabien
Ingénieur d'études en décisionnel
Inscription : septembre 2008
Messages : 5 686
Détails du profil
Informations personnelles :
Nom : Homme Fabien
Âge : 34
Localisation : France, Yvelines (Île de France)

Informations professionnelles :
Activité : Ingénieur d'études en décisionnel
Secteur : Arts - Culture

Informations forums :
Inscription : septembre 2008
Messages : 5 686
Points : 10 435
Points : 10 435
Envoyer un message via ICQ à Waldar Envoyer un message via Skype™ à Waldar
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(*).
__________________
Email : http://scr.im/waldar
Waldar est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/12/2011, 15h59   #12
Membre expérimenté
 
Homme Mohamed Houri
Inscription : mars 2010
Messages : 286
Détails du profil
Informations personnelles :
Nom : Homme Mohamed Houri
Localisation : France

Informations forums :
Inscription : mars 2010
Messages : 286
Points : 562
Points : 562
Citation:
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 :
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 :
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 :
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 :
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 :
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 Cordialement
www.hourim.wordpress.com
Mohamed.Houri est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/12/2011, 16h04   #13
Modérateur
 
Homme Fabien
Ingénieur d'études en décisionnel
Inscription : septembre 2008
Messages : 5 686
Détails du profil
Informations personnelles :
Nom : Homme Fabien
Âge : 34
Localisation : France, Yvelines (Île de France)

Informations professionnelles :
Activité : Ingénieur d'études en décisionnel
Secteur : Arts - Culture

Informations forums :
Inscription : septembre 2008
Messages : 5 686
Points : 10 435
Points : 10 435
Envoyer un message via ICQ à Waldar Envoyer un message via Skype™ à Waldar
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 :
1
2
3
4
FROM emp
     LEFT OUTER JOIN dept
       ON dept.deptno = emp.deptno
      AND dept.loc    = 'DALLAS'
__________________
Email : http://scr.im/waldar
Waldar est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/12/2011, 16h40   #14
Membre expérimenté
 
Homme Mohamed Houri
Inscription : mars 2010
Messages : 286
Détails du profil
Informations personnelles :
Nom : Homme Mohamed Houri
Localisation : France

Informations forums :
Inscription : mars 2010
Messages : 286
Points : 562
Points : 562
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 :
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 Cordialement
www.hourim.wordpress.com
Mohamed.Houri est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 29/12/2011, 10h10   #15
Membre habitué
 
Inscription : décembre 2004
Messages : 643
Détails du profil
Informations forums :
Inscription : décembre 2004
Messages : 643
Points : 104
Points : 104
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.
stof est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 29/12/2011, 11h40   #16
Modérateur
 
Homme Fabien
Ingénieur d'études en décisionnel
Inscription : septembre 2008
Messages : 5 686
Détails du profil
Informations personnelles :
Nom : Homme Fabien
Âge : 34
Localisation : France, Yvelines (Île de France)

Informations professionnelles :
Activité : Ingénieur d'études en décisionnel
Secteur : Arts - Culture

Informations forums :
Inscription : septembre 2008
Messages : 5 686
Points : 10 435
Points : 10 435
Envoyer un message via ICQ à Waldar Envoyer un message via Skype™ à Waldar
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.
__________________
Email : http://scr.im/waldar
Waldar est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 29/12/2011, 12h03   #17
Membre habitué
 
Inscription : décembre 2004
Messages : 643
Détails du profil
Informations forums :
Inscription : décembre 2004
Messages : 643
Points : 104
Points : 104
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?
stof est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 29/12/2011, 14h17   #18
Membre habitué
 
Inscription : décembre 2004
Messages : 643
Détails du profil
Informations forums :
Inscription : décembre 2004
Messages : 643
Points : 104
Points : 104
Il y a un truc qui ne "va pas" dès le début de la création des 2 branches parallèles :

Code :
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 :
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')
stof est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 29/12/2011, 14h21   #19
Modérateur
 
Homme Fabien
Ingénieur d'études en décisionnel
Inscription : septembre 2008
Messages : 5 686
Détails du profil
Informations personnelles :
Nom : Homme Fabien
Âge : 34
Localisation : France, Yvelines (Île de France)

Informations professionnelles :
Activité : Ingénieur d'études en décisionnel
Secteur : Arts - Culture

Informations forums :
Inscription : septembre 2008
Messages : 5 686
Points : 10 435
Points : 10 435
Envoyer un message via ICQ à Waldar Envoyer un message via Skype™ à Waldar
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.
__________________
Email : http://scr.im/waldar
Waldar est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 29/12/2011, 14h35   #20
Membre habitué
 
Inscription : décembre 2004
Messages : 643
Détails du profil
Informations forums :
Inscription : décembre 2004
Messages : 643
Points : 104
Points : 104
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)
stof est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 02h07.


 
 
 
 
Partenaires

Hébergement Web