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

PL/SQL Oracle Discussion :

performance : boucle et curseur


Sujet :

PL/SQL Oracle

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Février 2004
    Messages
    32
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Février 2004
    Messages : 32
    Par défaut performance : boucle et curseur
    Bonjour,

    Suite à une ORA-01555 (undo_retention étant la cause), je suis amené à modifier les dev de nos batch de nuit :
    d'un for sur curseur implicite (c'est lui qui reste trop longtemps ouvert) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    ...
    for rec in (select mes_champs from ma_table) loop
    begin
    mon_traitement(...);
    end;
    end loop;
    ...
    je passe à une boucle avec condition d'arret :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    ...
    while 1=1 loop
    begin
    open my_cursor for select mes_champs from ma_table where flag_treatment <> 'D' and rownum = 1 ;
    fetch my_cursor into rec;
    exit when my_cursor%NOTFOUND;
    update ma_table set flag_treatment = 'D';
    mon_traitement(...);
    close my_cursor;
    end;
    end loop;
    ...
    Les contraintes de prod imposent un changement du code, mais j'aimerais avoir vos avis quant à l'éventuelle perte de performance sur l'ouverture/fermeture de curseurs (sachant que le traitement intérieur est relativement lourd).

    D'avance merci,

    chmanu

  2. #2
    Invité
    Invité(e)
    Par défaut
    c'est sur que si tu fais une boucle juste pour mettre à jour un champ, c'est inutile et lourd pour rien, autant faire une requête globale.
    Après, il faut voir à quoi ressemble "mon_traitement(...); lourd" pour savoir si ce curseur est vraiment indispensable, difficile de parler davantage dans le vide.

    [edit]je viens de réaliser :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    ...
    while 1=1 loop
    begin
    open my_cursor FOR SELECT mes_champs FROM ma_table WHERE flag_treatment <> 'D' AND rownum = 1 ;
    fetch my_cursor INTO rec;
    exit when my_cursor%NOTFOUND;
    UPDATE ma_table SET flag_treatment = 'D';
    mon_traitement(...);
    close my_cursor;
    end;
    end loop;
    ...
    c'est du beau n'importe quoi !!! Une boucle infinie qui ouvre un curseur qui ne ramène qu'une ligne à la fois... Pourquoi faire simple ???

    essayez au moins quelque chose du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    ...
    open my_cursor FOR SELECT mes_champs FROM ma_table WHERE flag_treatment <> 'D'  ;
    fetch my_cursor INTO rec;
    exit when my_cursor%NOTFOUND;
    UPDATE ma_table SET flag_treatment = 'D';
    mon_traitement(...);
    close my_cursor;
    end;
    end loop;
    ...

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Février 2004
    Messages
    32
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Février 2004
    Messages : 32
    Par défaut
    Bonsoir,

    Je réalise que j'ai fait une erreur lors de la restitution de mon programme puisque le
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    UPDATE ma_table SET flag_treatment = 'D';
    est plutot :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    UPDATE ma_table SET flag_treatment = 'D' where id =rec.id;
    Mon_traitement(), que je n'ai pas détaillé, est un traitement à effectuer pour chacune des lignes de la table du curseur.
    D'où le curseur sur rownum=1.
    Pour donner une idée, mon_traitement() prends quelques dixiemes secondes, mais le batch concerne plusieurs centaines de milliers d'enregistrement.
    Ce qui fait que ca dure plusieurs heures (et c'est là que j avais mon curseur ouvert plusieurs heures)
    Votre proposition s'affranchit de la boucle, ce n'est pas la solution.

    La boucle est certe infinie, mais la condition d'arret se produira lorsque la table aura était traitée entièrement : ligne par ligne, je pose le flag_treatment à 'D' (erreur de retranscription).

    Merci tout de même.

  4. #4
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par chmanu Voir le message
    Mon_traitement(), que je n'ai pas détaillé, est un traitement à effectuer pour chacune des lignes de la table du curseur.
    D'où le curseur sur rownum=1.
    Pour donner une idée, mon_traitement() prends quelques dixiemes secondes, mais le batch concerne plusieurs centaines de milliers d'enregistrement.
    Ce qui fait que ca dure plusieurs heures (et c'est là que j avais mon curseur ouvert plusieurs heures)
    Votre proposition s'affranchit de la boucle, ce n'est pas la solution.
    Absolument pas, au lieu d'ouvrir un nouveau curseur pour traiter une ligne à la fois, j'ouvre un seul curseur global, qui traitera une ligne à la fois ensuite.
    Ou alors je n'ai pas bien compris votre besoin.
    Il serait bon de voir à quoi ressemble votre fameux traitement.

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Février 2004
    Messages
    32
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Février 2004
    Messages : 32
    Par défaut
    Absolument pas, au lieu d'ouvrir un nouveau curseur pour traiter une ligne à la fois, j'ouvre un seul curseur global, qui traitera une ligne à la fois ensuite.
    Ou alors je n'ai pas bien compris votre besoin.
    Il serait bon de voir à quoi ressemble votre fameux traitement.
    Oui, j'avais pensé à ca également, mais le fait d'ouvrir le curseur en début, pour fetcher dans la boucle ne reviendrait-il pas au même que ce que fait le curseur implicite dans mon for ?
    Je veux dire le curseur reste ouvert pendant 8h et mon undo_retention ne le permet pas.

  6. #6
    Expert confirmé
    Avatar de pachot
    Homme Profil pro
    Developer Advocate YugabyteDB
    Inscrit en
    Novembre 2007
    Messages
    1 822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : Suisse

    Informations professionnelles :
    Activité : Developer Advocate YugabyteDB
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2007
    Messages : 1 822
    Billets dans le blog
    1
    Par défaut
    Bonjour,

    Sur le principe, si le traitement du curseur et de l'update est négligeable par rapport au temps du gros traitement (du genre, 16 traitements de 30 minutes = 8 heures) c'est une bonne solution à mon avis.
    Sinon tu peux toujours faire un compromis en prenant les lignes 1000 par 1000 (rownum<=1000) par exemple.

    Par contre,
    - loop n'a pas besoin de 'while 1=1' pou rboucler
    - pas besoin d'un curseur explicite, un select into suffit

    Cordialement,
    Franck.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Performance boucle sur table tempo avec identity
    Par Jean.Cri1 dans le forum Adaptive Server Enterprise
    Réponses: 7
    Dernier message: 31/08/2011, 11h42
  2. Améliorer performance boucle vba
    Par mouncefdi dans le forum Macros et VBA Excel
    Réponses: 15
    Dernier message: 09/03/2009, 22h15
  3. Procédure, boucle et curseur pour une débutante
    Par menel_dev dans le forum PL/SQL
    Réponses: 10
    Dernier message: 24/02/2009, 09h54
  4. Procédure SQL : Boucle sur CURSEUR
    Par Yakaldir dans le forum DB2
    Réponses: 5
    Dernier message: 10/03/2007, 15h56
  5. [Oracle 9i] boucle et curseur
    Par Requin15 dans le forum Oracle
    Réponses: 18
    Dernier message: 20/06/2006, 19h32

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