MERGE vs NESTED LOOP, ma base ne répond plus... - SQL/NoSQL - Programmation
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) */ ... ?
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)...