|
Publicité | |||||||||||||||||||||||
|
|
#1 |
|
Candidat au titre de Membre du Club
![]() Inscription: décembre 2006
Messages: 28
|
Bonjour à tous.
J'ai besoin de votre aide sur une procédure qui met un certain temps à s'exécuter. Je pense avoir repérer l'instruction qui pose problème : Code :
SELECT MAX(VOL.JOUR), MIN(VOL.JOUR) INTO LD$MAXDATE, LD$MINDATE FROM RF_VOLUMEPREPREAL VOL WHERE VOL.CODE_ETABLISSEMENT = curETB.CODE AND VOL.CIRCUITPREPARATION = curCP.CODE AND VOL.POINTDEVENTE = curPDV.CODE AND VOL.JOUR > LD$MINDATE AND VOL.REFERENTIEL = LN$IDREF; Code :
INSERT INTO RF_VOLUMEPREPREAL (CIRCUITPREPARATION, POINTDEVENTE, REFERENTIEL, UO, CODE_ETABLISSEMENT, PROG_WRITER, JOUR) SELECT curCP.CODE, curPDV.CODE, LN$IDREF, LN$VALEUR, curETB.CODE, LC$TAG_UPDATABLE, JOUR.DATE_CALENDRIER FROM RF_JOUR JOUR WHERE JOUR.DATE_CALENDRIER NOT IN( SELECT VOL.JOUR FROM RF_VOLUMEPREPREAL VOL WHERE VOL.CODE_ETABLISSEMENT = curETB.CODE AND VOL.CIRCUITPREPARATION = curCP.CODE AND VOL.POINTDEVENTE = curPDV.CODE AND VOL.JOUR BETWEEN LD$MINDATE AND LD$MAXDATE AND VOL.REFERENTIEL = LN$IDREF) AND JOUR.DATE_CALENDRIER BETWEEN LD$MINDATE AND LD$MAXDATE; La table RF_VOLUMEPREPREAL contient un grand nombre d'enregistrements (environ 10 millions). Elle contient des UO par jour. Or, tous les jours ne sont pas renseignés. Ma procédure consiste donc à "boucher les trous" par des 0 entre les dates retournées par la première requête. Je crois que le problème vient du fait que je fais un insert sur un table qui est elle même interrogée par le select... Merci de votre aide. Dernière modification par Superdub ; 19/05/2009 à 14h56. |
|
|
00
|
|
|
#2 |
|
Membre actif
![]() Inscription: janvier 2006
Localisation: Alès (Gard)
Âge: 31
Messages: 179
|
En général, Oracle n'aime pas les NOT IN ... Et si on essayait un NOT EXISTS ?
Code :
INSERT INTO RF_VOLUMEPREPREAL
(CIRCUITPREPARATION, POINTDEVENTE, REFERENTIEL, UO, CODE_ETABLISSEMENT, PROG_WRITER, JOUR)
SELECT curCP.CODE, curPDV.CODE, LN$IDREF, LN$VALEUR, curETB.CODE, LC$TAG_UPDATABLE, JOUR.DATE_CALENDRIER
FROM RF_JOUR JOUR
WHERE NOT EXISTS(
SELECT NULL
FROM RF_VOLUMEPREPREAL VOL
WHERE VOL.JOUR = JOUR.DATE_CALENDRIER
AND VOL.CODE_ETABLISSEMENT = curETB.CODE
AND VOL.CIRCUITPREPARATION = curCP.CODE
AND VOL.POINTDEVENTE = curPDV.CODE
AND VOL.JOUR BETWEEN LD$MINDATE AND LD$MAXDATE
AND VOL.REFERENTIEL = LN$IDREF)
AND JOUR.DATE_CALENDRIER BETWEEN LD$MINDATE AND LD$MAXDATE;
|
|
|
00
|
|
|
#3 |
![]() Inscription: octobre 2007
Messages: 2 256
|
|
|
|
00
|
|
|
#4 | ||
|
Membre actif
![]() Inscription: janvier 2006
Localisation: Alès (Gard)
Âge: 31
Messages: 179
|
Citation:
Cela ne s'appuie effectivement que sur mon expérience personnelle (sous Oracle 10gR1 et R2). Dans un cas comme celui-ci, il est bon d'essayer le NOT IN et le NOT EXISTS et de les comparer. De ma propre expérience, Oracle a mieux géré le NOT EXISTS de l'ordre de 9 fois sur 10, je préfère donc maintenant commencer par le NOT EXISTS et me tourner vers le NOT IN si je rencontre un souci, plutôt que l'inverse Maintenant cela dépend bien entendu de la requête, de la version d'Oracle, des données, des indexes... D'une manière générale quand une requête rencontre des problèmes de performance, il est bon d'essayer d'autres façons de l'écrire (tout en analysant le plan d'exécution et en indexant mieux si nécessaire). Je reformule : Citation:
|
||
|
|
00
|
|
|
#5 |
|
Candidat au titre de Membre du Club
![]() Inscription: décembre 2006
Messages: 28
|
Merci beaucoup pour la réponse, je commence à désespérer avec mes problèmes de performances (eh oui, ce n'est pas le seul, new topic coming soon
Voici le EXPLAIN PLAN pour le NOT IN : Code :
-------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 566 | 30564 | 6 (17)| 00:00:01 | |* 1 | HASH JOIN RIGHT ANTI | | 566 | 30564 | 6 (17)| 00:00:01 | |* 2 | TABLE ACCESS BY INDEX ROWID| RF_VOLUMEPREPREAL | 1 | 46 | 2 (0)| 00:00:01 | |* 3 | INDEX RANGE SCAN | SYS_C0013284 | 1 | | 2 (0)| 00:00:01 | |* 4 | INDEX RANGE SCAN | SYS_C0013202 | 567 | 4536 | 3 (0)| 00:00:01 | -------------------------------------------------------------------------------------------------- Predicate Information (IDENTIFIED BY operation id): --------------------------------------------------- 1 - access("JOUR"."DATE_CALENDRIER"="VOL"."JOUR") 2 - filter("VOL"."CODE_ETABLISSEMENT"='011') 3 - access("VOL"."REFERENTIEL"=6 AND "VOL"."POINTDEVENTE"='01105' AND "VOL"."CIRCUITPREPARATION"='000001415' AND "VOL"."JOUR">=TO_DATE('2007-11-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss') AND "VOL"."JOUR"<=TO_DATE('2009-05-19 00:00:00', 'yyyy-mm-dd hh24:mi:ss')) 4 - access("JOUR"."DATE_CALENDRIER">=TO_DATE('2007-11-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss') AND "JOUR"."DATE_CALENDRIER"<=TO_DATE('2009-05-19 00:00:00', 'yyyy-mm-dd hh24:mi:ss')) 24 rows selected Code :
-------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 566 | 30564 | 6 (17)| 00:00:01 | |* 1 | HASH JOIN RIGHT ANTI | | 566 | 30564 | 6 (17)| 00:00:01 | |* 2 | TABLE ACCESS BY INDEX ROWID| RF_VOLUMEPREPREAL | 1 | 46 | 2 (0)| 00:00:01 | |* 3 | INDEX RANGE SCAN | SYS_C0013284 | 1 | | 2 (0)| 00:00:01 | |* 4 | INDEX RANGE SCAN | SYS_C0013202 | 567 | 4536 | 3 (0)| 00:00:01 | -------------------------------------------------------------------------------------------------- Predicate Information (IDENTIFIED BY operation id): --------------------------------------------------- 1 - access("VOL"."JOUR"="JOUR"."DATE_CALENDRIER") 2 - filter("VOL"."CODE_ETABLISSEMENT"='011') 3 - access("VOL"."REFERENTIEL"=6 AND "VOL"."POINTDEVENTE"='01105' AND "VOL"."CIRCUITPREPARATION"='000001415' AND "VOL"."JOUR">=TO_DATE('2007-11-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss') AND "VOL"."JOUR"<=TO_DATE('2009-05-19 00:00:00', 'yyyy-mm-dd hh24:mi:ss')) 4 - access("JOUR"."DATE_CALENDRIER">=TO_DATE('2007-11-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss') AND "JOUR"."DATE_CALENDRIER"<=TO_DATE('2009-05-19 00:00:00', 'yyyy-mm-dd hh24:mi:ss')) 24 rows selected Mais j'ai bien l'impression que rien ne change entre les deux versions ... |
|
|
00
|
|
|
#6 |
|
Membre éprouvé
![]() Inscription: juillet 2007
Localisation: Paris
Messages: 476
|
Est-ce que tourné comme ça, ça fait améliorer le schmilblcik ?
Code :
INSERT INTO RF_VOLUMEPREPREAL (CIRCUITPREPARATION, POINTDEVENTE, REFERENTIEL, UO, CODE_ETABLISSEMENT, PROG_WRITER, JOUR) SELECT curCP.CODE, curPDV.CODE, LN$IDREF, LN$VALEUR, curETB.CODE, LC$TAG_UPDATABLE, JOUR.DATE_CALENDRIER FROM RF_JOUR JOUR WHERE JOUR.DATE_CALENDRIER IN (SELECT DATE_CALENDRIER FROM RF_JOUR MINUS SELECT VOL.JOUR FROM RF_VOLUMEPREPREAL VOL WHERE VOL.CODE_ETABLISSEMENT = curETB.CODE AND VOL.CIRCUITPREPARATION = curCP.CODE AND VOL.POINTDEVENTE = curPDV.CODE AND VOL.JOUR BETWEEN LD$MINDATE AND LD$MAXDATE AND VOL.REFERENTIEL = LN$IDREF) AND JOUR.DATE_CALENDRIER BETWEEN LD$MINDATE AND LD$MAXDATE;
__________________
Des chercheurs qui cherchent, on en trouve, mais des chercheurs qui trouvent, on en cherche ! |
|
|
00
|
|
|
#7 |
|
Candidat au titre de Membre du Club
![]() Inscription: décembre 2006
Messages: 28
|
Merci pour la réponse.
D'après le EXPLAIN PLAN, cette méthode n'améliore pas les performances mais c'était bien vu ! Code :
----------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 220 | 3740 | 7 (29)| 00:00:01 | | 1 | NESTED LOOPS | | 220 | 3740 | 7 (29)| 00:00:01 | | 2 | VIEW | VW_NSO_1 | 567 | 5103 | 7 (29)| 00:00:01 | | 3 | MINUS | | | | | | | 4 | SORT UNIQUE | | 567 | 4536 | | | |* 5 | INDEX RANGE SCAN | SYS_C0013202 | 567 | 4536 | 3 (0)| 00:00:01 | | 6 | SORT UNIQUE | | 1 | 46 | | | |* 7 | TABLE ACCESS BY INDEX ROWID| RF_VOLUMEPREPREAL | 1 | 46 | 2 (0)| 00:00:01 | |* 8 | INDEX RANGE SCAN | SYS_C0013284 | 1 | | 2 (0)| 00:00:01 | |* 9 | INDEX UNIQUE SCAN | SYS_C0013202 | 1 | 8 | 0 (0)| 00:00:01 | ----------------------------------------------------------------------------------------------------- Predicate Information (IDENTIFIED BY operation id): --------------------------------------------------- 5 - access("DATE_CALENDRIER">=TO_DATE('2007-11-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss') AND "DATE_CALENDRIER"<=TO_DATE('2009-05-19 00:00:00', 'yyyy-mm-dd hh24:mi:ss')) 7 - filter("VOL"."CODE_ETABLISSEMENT"='011') 8 - access("VOL"."REFERENTIEL"=6 AND "VOL"."POINTDEVENTE"='01105' AND "VOL"."CIRCUITPREPARATION"='000001415' AND "VOL"."JOUR">=TO_DATE('2007-11-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss') AND "VOL"."JOUR"<=TO_DATE('2009-05-19 00:00:00', 'yyyy-mm-dd hh24:mi:ss')) 9 - access("JOUR"."DATE_CALENDRIER"="$nso_col_1") filter("JOUR"."DATE_CALENDRIER"<=TO_DATE('2009-05-19 00:00:00', 'yyyy-mm-dd hh24:mi:ss') AND "JOUR"."DATE_CALENDRIER">=TO_DATE('2007-11-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss')) 31 rows selected |
|
|
00
|
|
|
#8 |
![]() Inscription: octobre 2007
Messages: 2 256
|
|
|
|
00
|
|
|
#9 |
|
Membre éprouvé
![]() Inscription: août 2008
Âge: 29
Messages: 464
|
Salut,
Il nous faudrait plus d'information. C'est quoi "une procédure qui met un certain temps à s'exécuter" et quel est le temps maximal souhaité. Sinon concernant tes requêtes, c'est quoi curETB, curCP, curPDV, des curseurs ? Si c'est le cas en as tu vraiment besoin, parceque des curseurs sur des tables de 10 millions de lignes c'est très contre performant. |
|
|
00
|
|
|
#10 | |
![]() |
Citation:
Comme il y en a beaucoup ça prend du temps même si l'insert en lui-même se passe bien. Solution : faire de l'ensembliste ! Edit : grilled ! |
|
|
00
|
|
|
#11 |
|
Candidat au titre de Membre du Club
![]() Inscription: décembre 2006
Messages: 28
|
Pour expliquer, ma base de données contient des établissements (ETB), qui possède des circuits de préparation (CP), qui sont reliés à des points de vente (PDV). Pour chaque triplet ETB, CP, PDV sont associés un UO par JOUR.
Ces UO sont renseignés partiellement dans la table RF_VOLUMEPREPREAL par chargement de fichier. (Tous les jours ne sont pas renseignés pour chaque triplet). Il faut donc combler les jours manquant par des 0. Je fais donc : Pour chaque ETB Pour chaque CP(ETBCourant) Pour chaque PDV(CPCourant) Insertion de 0 pour les dates manquantes. Pour les temps de traitement, au terme du remplissage partiel, 10 Millions de lignes sont renseignées dans la table RF_VOLUMEPREPREAL, ce qui représente environ 20%, les 80% restants étant complétés par cette procédure. Actuellement cette procédure s'effectue en une dizaine d' heures ... |
|
|
00
|
|
|
#12 |
![]() |
Ce qui plombe vos performances c'est le triple curseur.
Vous pouvez (devez) probablement arriver à vos fins en une seule et unique requête. Essayez ceci en étant raisonnable sur la plage de date : Code :
SELECT v.circuitpreparation, v.pointdevente ln$idref, ln$valeur, v.code_etablissement, lc$tag_updatable, j.date_calendrier FROM rf_volumeprepreal v PARTITION BY (code_etablissement, circuitpreparation, pointdevente) RIGHT OUTER JOIN rf_jour j ON j.date_calendrier = v.jour WHERE j.date_calendrier BETWEEN ld$mindate AND ld$maxdate AND v.jour IS NULL |
|
00
|
|
|
#13 |
|
Membre éprouvé
![]() Inscription: août 2008
Âge: 29
Messages: 464
|
C'était donc bien un euphémisme
Suis les conseils de Waldar, ton problème sur la vue me dis que tu peux adapter ta procédure seul, mais si tu as des difficultés, post le code de la proc. [EDIT]:Y a même plus qu'un conseil
|
|
|
00
|
|
|
#14 | |
![]() Inscription: octobre 2007
Messages: 2 256
|
Citation:
C'est un peu à ça que je pensait moi aussi, mais je voudrais que quelque'un le dise. Et ce n'est pas ça ? Sinon, j'ai une autre question (après avoir lu le réponse): Et pour quoi veut-on inserer des 0 pour les dates manquantes ? [Edit] Ca va vite sur ce sujet [/Edit] |
|
|
|
00
|
|
|
#15 |
|
Candidat au titre de Membre du Club
![]() Inscription: décembre 2006
Messages: 28
|
Merci waldar pour cette requête. Je viens de la tester et elle s'exécute très vite (environ 10 secondes). Il ne me reste plus qu'à la coupler avec le insert et le tour est joué. Je reviens vers vous plus tard pour vous donner mes conclusions.
Merci. [EDIT] Arf, après étude, ça correspond en partie à ce que je voulais ... Je vais rajouter deux difficultés :
Désolé, j'aurais du donner ces précisions un peu plus tot... Dernière modification par Superdub ; 19/05/2009 à 17h43. |
|
|
00
|
|
|
#16 |
![]() |
Mon tarif est de 1 € par seconde gagnée
|
|
00
|
|
|
#17 |
![]() Inscription: octobre 2007
Messages: 2 256
|
Mais, je reste persuadé qu'en fait il n'y nul besoin de cette procédure
|
|
|
00
|
|
|
#18 |
|
Candidat au titre de Membre du Club
![]() Inscription: décembre 2006
Messages: 28
|
Houlala
Sinon, avec l'ajout d'une nouvelle page sur le topic, je précise que j'ai édité le message d'avant pour corser l'affaire @mnitu : si, si rassure toi, elle a son utilité |
|
|
00
|
|
|
#19 |
![]() |
Est-ce que vous utilisez toujours la table RF_VOLUMEPREPREAL pour faire votre triplet ou bien avez-vous des tables de référence dédiées ?
|
|
00
|
|
|
#20 |
|
Candidat au titre de Membre du Club
![]() Inscription: décembre 2006
Messages: 28
|
Il y a une table ETABLISSEMENT. Et une table pour les couples CP et PDV selon un referentiel (il y plusieurs référentiels par établissement, ici, un seul nous interesse).
Je pense que je peux faire une vue répertoriant l'ensemble des triplets pour le référentiel qui nous intéresse. Je posterai demain cette vue. |
|
|
00
|