MERGE vs NESTED LOOP, ma base ne répond plus...

MERGE vs NESTED LOOP, ma base ne répond plus... - SQL/NoSQL - Programmation

Marsh Posté le 04-03-2011 à 15:41:23    

Bonjour tout le monde,
 
J'ai un problème très étrange sous Oracle 9i :  
 
 
Objectif de la requête :  
Trouver la quantité vendue pour un article CARTICLE après une date donnée DDEB_ANALYSE_MNC pour les ventes ayant eu lieu en saison...
 
Pour faire plus clair, un petit axe de temps :  
 
Ma date de 1ère vente de l'article est au 05/04/2008
La date à partir de laquelle je souhaite analyser est le 01/02/2009 (cette date est calculée auparavant)
 
 
Année 2008
|--|--|--|*-|XX|XX|--|--|--|--|--|--|
 
* : date de première vente (05/04/2008)
XX représente une période en saison (ici, on est en saison du 01/05 au 30/06, quelque soit l'année)
 
 
Année 2009
|--|*-|--|--|XX|XX|--|--|--|--|--|--|
 
* : date de début d'analyse (01/02/2009)
XX représente une période en saison (ici, on est en saison du 01/05 au 30/06)
 
 
Année 2010
|--|--|--|--|XX|XX|--|--|--|--|--|--|
 
XX représente une période en saison (ici, on est en saison du 01/05 au 30/06)
 
 
Année 2011
|--|--|*-|--|XX|XX|--|--|--|--|--|--|
 
* : date de fin d'analyse : date du jour
XX représente une période en saison (ici, on est en saison du 01/05 au 30/06)
 
Pour ces calculs, j'ai donc :  
 
MJOUR_DEBUT_SAISON : jour de début de période de saison, valeur = 1
MMOIS_DEBUT_SAISON : mois de début de période de saison, valeur = 5
MJOUR_FIN_SAISON : jour de fin de période de saison, valeur = 30
MMOIS_FIN_SAISON : mois de fin de période de saison, valeur = 6
DDEB_ANALYSE_MNC : date à laquelle je commence à comptabiliser les ventes
TMODIFICATION : si il est à 2, la donnée est supprimée logiquement, on n'en tient pas compte
DMODIFICATION : date de la vente
QVENDUE : quantité vendue à une date (aggrégat quotidien)
 
 
Requête qui passe en environ 0,1 sec :  


SELECT  
       ASE.QVENDUE,
       XBA.CARTICLE,  
       ASE.DMODIFICATION,
       XBA.DDEB_ANALYSE_MNC,
       NMS.MJOUR_DEBUT_SAISON,
       NMS.MMOIS_DEBUT_SAISON,
       NMS.MJOUR_FIN_SAISON,
       NMS.MMOIS_FIN_SAISON
FROM ARTICLE_SEMAINE ASE --contient les ventes aggrégées par jour
     INNER JOIN XBA_TST XBA ON XBA.CARTICLE = ASE.CARTICLE  --XBA_TST est ma table de test
     INNER JOIN ARTICLE.NSAISON NMS ON NMS.CNMODULE = XBA.CNMODULE --NSAISON contient mes périodes de saison
           AND NMS.TMODIFICATION <> 2  
WHERE XBA.CARTICLE = 65286  --filtre pour test, je ne regarde qu'un article pour le moment
      AND ASE.DMODIFICATION >= XBA.DDEB_ANALYSE_MNC  --filtre pour date, je ne m'interesse qu'aux dates > DDEB_ANALYSE_MNC
      --liste des critères pour qu'une vente soit en saison
      --jour de vente >= jour de début de saison
      AND to_number(to_char(ASE.DMODIFICATION, 'DD')) >= NMS.MJOUR_DEBUT_SAISON
      --mois de vente >= mois de début de saison
      AND to_number(to_char(ASE.DMODIFICATION, 'MM')) >= NMS.MMOIS_DEBUT_SAISON
      --jour de vente <= jour de fin de saison
      AND to_number(to_char(ASE.DMODIFICATION, 'DD')) <= NMS.MJOUR_FIN_SAISON  


 
A ce stade, tout va bien, mais on remarque qu'il manque un critère, que je rajoute dans cette requête :  


SELECT  
       ASE.QVENDUE,
       XBA.CARTICLE,  
       ASE.DMODIFICATION,
       XBA.DDEB_ANALYSE_MNC,
       NMS.MJOUR_DEBUT_SAISON,
       NMS.MMOIS_DEBUT_SAISON,
       NMS.MJOUR_FIN_SAISON,
       NMS.MMOIS_FIN_SAISON
FROM ARTICLE_SEMAINE ASE
     INNER JOIN XBA_TST XBA ON XBA.CARTICLE = ASE.CARTICLE
     INNER JOIN ARTICLE.NSAISON NMS ON NMS.CNMODULE = XBA.CNMODULE  
           AND NMS.TMODIFICATION <> 2  
WHERE XBA.CARTICLE = 65286
      AND ASE.DMODIFICATION >= XBA.DDEB_ANALYSE_MNC  
      --liste des critères pour qu'une vente soit en saison
      --jour de vente >= jour de début de saison
      AND to_number(to_char(ASE.DMODIFICATION, 'DD')) >= NMS.MJOUR_DEBUT_SAISON
      --mois de vente >= mois de début de saison
      AND to_number(to_char(ASE.DMODIFICATION, 'MM')) >= NMS.MMOIS_DEBUT_SAISON
      --jour de vente <= jour de fin de saison
      AND to_number(to_char(ASE.DMODIFICATION, 'DD')) <= NMS.MJOUR_FIN_SAISON  
      --mois de vente <= mois de fin de saison
      AND to_number(to_char(ASE.DMODIFICATION, 'MM')) <= NMS.MMOIS_FIN_SAISON --critère ajouté


et là, c'est le drame, ça ne répond plus (enfin, j'ai laissé tourner 1 min)...  
 
Je vous mets les explain plan des 2 requêtes :  
 
REQUETE 1, répond bien :  


DESC    OWNER NAME   COST CARD BYTES
 
SELECT STATEMENT, GOAL = CHOOSE     177 1 61
 MERGE JOIN       177 1 61
  SORT JOIN       72 3 78
   MERGE JOIN       65 3 78
    SORT JOIN       51 21 273
     TABLE ACCESS BY INDEX ROWIDAPPRO ARTICLE_SEMAINE  44 21 273
      INDEX SKIP SCAN  APPRO PK_ARTICLE_SEMAINE 24 21  
    FILTER      
     SORT JOIN      
      TABLE ACCESS FULL  ARTICLE NSAISON   4 1004 13052
  FILTER      
   SORT JOIN      
    TABLE ACCESS FULL  APPRO XBA_TST   96 368 12880


REQUETE 2, ne répond pas :  


DESC    OWNER NAME   COST CARD BYTES
 
SELECT STATEMENT, GOAL = CHOOSE     161 1 61
 NESTED LOOPS       161 1 61
  MERGE JOIN       65 1 26
   SORT JOIN       51 21 273
    TABLE ACCESS BY INDEX ROWID APPRO ARTICLE_SEMAINE  44 21 273
     INDEX SKIP SCAN  APPRO PK_ARTICLE_SEMAINE 24 21  
   FILTER      
    SORT JOIN      
     TABLE ACCESS FULL  ARTICLE NSAISON   4 1004 13052
  TABLE ACCESS FULL  APPRO XBA_TST   96 1 35


 
Voila voila, ça m'intéresserait bien de comprendre pourquoi en ajoutant ce critère supplémentaire, mon explain plan change complètement et ma requête ne répond plus...
J'ai essayé en mettant le critère :
      AND to_number(to_char(ASE.DMODIFICATION, 'MM')) <= NMS.MMOIS_FIN_SAISON --critère ajouté
avant les 3 autres critères de date, ça ne change rien...
(pour résumer, ce n'est pas CE crtitère qui pose problème, mais le fait que je rajoute un 4è critère)...

Reply

Marsh Posté le 04-03-2011 à 15:41:23   

Reply

Marsh Posté le 08-03-2011 à 15:53:02    

Salut,
 
tes statistiques de tables sont à jour ?
 
quelles sont les clefs sur tes tables ?  
parce que de toute façon, dans les 2 cas le skip scan sur la PK de la table ARTICLE_SEMAINE montre que tu n'as pas la ou les premières valeurs de clef dans tes conditions, ce qui n'est pas optimum.
 
que te donne dans le 2eme cas, le plan d'exécution si tu rajoutes dans ta requête le hint suivant : select /*+ USE_HASH(XBA) */ ...  ?

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed