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 :

probleme rowcount avec Forall


Sujet :

PL/SQL Oracle

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Inscrit en
    Mars 2004
    Messages
    137
    Détails du profil
    Informations forums :
    Inscription : Mars 2004
    Messages : 137
    Par défaut probleme rowcount avec Forall
    Bonjour,

    Je suis en 10g et j'utilise le pl/sql.

    J'utilise un bulk avec un limite 200 pour un de mes programmes de mises à jours. J'ai environ 300000 enregistrement à traiter.

    suite à mon bulk dans des tableaux, j'utilise forall pour faire un update. Juste après, j'utilise sql%rowcount pour savoir si je fais un certain traitement qui doit se faire toute les 2000 enregistrements... mais voilà que le rowcount semble échappé des transactions à certain moment. c'est à dire qu'apres plusieurs milliers de record je remarque que le sql%rowcount me retourne 199 au lieu de 200... cela arrive à plusieurs reprise durant le traitement donc à la fin c'est comme si j'avais un décalage de 50 enregistrements...

    Le probleme semble aléatoire d'une fois à l'autre... alors je ne sais plus quoi penser... est-ce un problème connu? est-ce que vous voyez une alternative?

    merci

  2. #2
    Expert confirmé Avatar de mnitu
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2007
    Messages
    5 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2007
    Messages : 5 611

  3. #3
    Membre confirmé
    Inscrit en
    Mars 2004
    Messages
    137
    Détails du profil
    Informations forums :
    Inscription : Mars 2004
    Messages : 137
    Par défaut
    ce que je comprend c'est que tu me dis d'utiliser le SQL%BULK_ROWCOUNT(i). Mais comme le I fait référence au counteur du bulk et bien ce n'est pas vraiment mon besoin... j'ai besoin de savoir combien d'enregistrement ont été updater avec mon FORALL update... en principe, il devrait y en avoir 200 jusqu'avant la fin à moins que les condition du update ne soit pas répondu... mais comme le where clause est le meme que celui du select de mon bulk... je ne vois pas pourquoi il en sauterais...

    est-ce que je comprends bien ce que tu souhaitait m'expliquer... je ne suis pas sur que ce soit ca que j'ai besoin à moins que je ne comprenne pas bien comment ca fonctionne.

    merci

  4. #4
    Expert confirmé Avatar de mnitu
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2007
    Messages
    5 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2007
    Messages : 5 611
    Par défaut
    Oui c'est ça. Maintenant ça pourrait aller mieux avec un petit exemple.
    Si je comprends bien, votre problème est que des enregistrements semble disparaitre du traitement.
    Cella pourrait s'expliquer si des autres transactions modifient en même temps les données utilisées par votre traitement:
    1) Vous chargez 200 lignes qui correspondent à vos critères dans un tableau sans les verrouiller.
    2) Une autre transaction commit une modification pour une de colonnes utilisées comme critère de sélection d'une de vos lignes.
    3) Vous faite l'update avec les mêmes critères que le select mais maintenant la ligne n'a plus la valeur de début dans la base.

  5. #5
    Membre confirmé
    Inscrit en
    Mars 2004
    Messages
    137
    Détails du profil
    Informations forums :
    Inscription : Mars 2004
    Messages : 137
    Par défaut
    ca aurait tres bien pu etre ca... mais c'est un environnement de dev dont je suis le seul utilisateur... donc... je ne comprend pas trop...

    par contre... le sql%ROWCOUNT utilisé apres un update... retourne bien le nombre d'update effectué? donc si dans une boucle donnée l'update correspondant au where-clause correspond seulement à 199 sur 200, le sql%rowcount devrait me retourné 199 au lieu du 200 attendu pour cette fois là n'est-ce pas ?

    Si on fait un parrallele avec le SQL%BULK_ROWCOUNT(i)... ne devrait-il pas toujours me retourné 200 puisque la limite du bulk est 200? si oui, ca n'a aucun rapport avec l'update je me trompe?

  6. #6
    Expert confirmé Avatar de mnitu
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2007
    Messages
    5 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2007
    Messages : 5 611
    Par défaut
    Le SQL%ROWCOUNT ne peut être utilisé qu’après l’instruction FORALL. Il vous donne le nombre total, cumulative des enregistrements modifié par le FORALL. Voilà un exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
     
    Connected to Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 
    Connected as mni
     
    SQL> set serveroutput on
    SQL> 
    SQL> Declare
      2    Cursor crs Is
      3    Select department_id
      4      From hr.departments d;
      5    --
      6    Type dept_aa Is Table Of Integer Index By Pls_Integer;
      7    l_tdept        dept_aa;
      8  Begin
      9    Open crs;
     10    Fetch crs  Bulk Collect Into l_tdept Limit 10;
     11    --
     12    ForALL i In 1..l_tdept.Count()
     13      Update hr.departments d
     14        Set d.department_name = Upper(d.department_name)
     15       Where d.department_id = l_tdept(i);
     16    For i In 1..l_tdept.count() Loop
     17      Dbms_Output.put_line('Lignes modifiées dans itération ('||To_Char(i)||') = '||To_Char(SQL%BULK_ROWCOUNT(i)));
     18    End Loop;
     19    --
     20    Dbms_Output.put_line('Total lignes modifiées = '||To_Char(SQL%ROWCOUNT));
     21    --
     22    Close crs;
     23    --
     24    Rollback;
     25  End;
     26  /
     
    Lignes modifiées dans itération (1) = 1
    Lignes modifiées dans itération (2) = 1
    Lignes modifiées dans itération (3) = 1
    Lignes modifiées dans itération (4) = 1
    Lignes modifiées dans itération (5) = 1
    Lignes modifiées dans itération (6) = 1
    Lignes modifiées dans itération (7) = 1
    Lignes modifiées dans itération (8) = 1
    Lignes modifiées dans itération (9) = 1
    Lignes modifiées dans itération (10) = 1
    Total lignes modifiées = 10
     
    PL/SQL procedure successfully completed
     
    SQL>

  7. #7
    Membre éclairé
    Inscrit en
    Novembre 2002
    Messages
    549
    Détails du profil
    Informations forums :
    Inscription : Novembre 2002
    Messages : 549
    Par défaut
    Bonjour

    Ajoute un save exceptions à ton forall

    Exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    DECLARE--[EXCEPTION_INIT pour le FORALL]
       forall_dml_errors EXCEPTION;
       PRAGMA EXCEPTION_INIT(forall_dml_errors, -24381);
    BEGINBEGIN        
       FORALL I IN  TAB_DBA_M.FIRST.. TAB_DBA_M.LAST SAVE EXCEPTIONS
         INSERT INTO T_DBA(TDBA_M, TDBA_SZ,TDBA_SU) VALUES( TAB_DBA_M (I) ,TAB_DBA_SZ (I),TAB_DBA_SU (I) );
        COMMIT;
     
       EXCEPTION
         WHEN forall_dml_errors THEN
           l_error_count_insert := SQL%BULK_EXCEPTIONS.count;
           DBMS_OUTPUT.put_line('Nombre d''erreur(s)  : ' || l_error_count_insert);
           FOR i IN 1 .. l_error_count_insert LOOP
             DBMS_OUTPUT.put_line('Erreur remontée: ' || i ||
              ' Index de la collection : ' || SQL%BULK_EXCEPTIONS(i).error_index ||
              ' Message: ' || SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE));
           END LOOP;
       END;
     
    END;

  8. #8
    Candidat au Club
    Profil pro
    Inscrit en
    Mai 2009
    Messages
    3
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2009
    Messages : 3
    Par défaut Cause de perte d'enregistrements !
    Citation Envoyé par juin29 Voir le message
    Bonjour,

    Je suis en 10g et j'utilise le pl/sql.

    J'utilise un bulk avec un limite 200 pour un de mes programmes de mises à jours. J'ai environ 300000 enregistrement à traiter.

    suite à mon bulk dans des tableaux, j'utilise forall pour faire un update. Juste après, j'utilise sql%rowcount pour savoir si je fais un certain traitement qui doit se faire toute les 2000 enregistrements... mais voilà que le rowcount semble échappé des transactions à certain moment. c'est à dire qu'apres plusieurs milliers de record je remarque que le sql%rowcount me retourne 199 au lieu de 200... cela arrive à plusieurs reprise durant le traitement donc à la fin c'est comme si j'avais un décalage de 50 enregistrements...

    Le probleme semble aléatoire d'une fois à l'autre... alors je ne sais plus quoi penser... est-ce un problème connu? est-ce que vous voyez une alternative?

    merci
    Le problème est probablement dû au fait que vous utilisez cursor%notfound pour sortir de votre boucle, ce qui engendrerait la perte d’enregistrements non traités.

    Voici un exemple simple montrant pourquoi des enregistrements échappent au traitement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    create table test_table (col1 number, col2 varchar2(20));
    Alimenter la table juste pour notre test :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    begin
    for i in 1..17
    loop
    insert into test_table (col1, col2)
    values (i, 'ligne '||i);
    end loop;
    commit;
    end;
    Maintenant essayons de voir pourquoi des enregistrements ne sont pas traités :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
    declare
    type num_tab is table of number index by pls_integer;
    n_t num_tab;
     
    cursor c 
    is
    select TT.COL1
    from test_table tt;
    begin
    open c;
    loop
    fetch c bulk collect into n_t limit 10;
    exit when c%notfound;
    --exit when n_t.count = 0;
    for i in 1..n_t.count
    loop 
    dbms_output.put_line(n_t(i));
    end loop;
    end loop;
    close c;
     
    end;
    1er cas : Condition de sortie : exit when c%notfound;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Nous remarquons que les sept derniers enregistrements ne sont pas traités.
    A la deuxième itération, il y’a sortie de la boucle, il n’a pas d’enregistrement 18ème, les 10 enregistrements suivants ne sont donc pas traités.

    2ème cas : Condition de sortie : exit when n_t.count=0;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

    Nous remarquons que la totalité des enregistrements est traitée.

  9. #9
    Rédacteur

    Homme Profil pro
    Consultant / formateur Oracle et SQL Server
    Inscrit en
    Décembre 2002
    Messages
    3 461
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Consultant / formateur Oracle et SQL Server

    Informations forums :
    Inscription : Décembre 2002
    Messages : 3 461
    Par défaut
    Citation Envoyé par s.houali Voir le message
    Le problème est probablement dû au fait que vous utilisez cursor%notfound pour sortir de votre boucle
    Il est vrai que le point que vous soulevez est un attrape couillon de première classe : "LIMIT n" provoque un %NOTFOUND s'il ne reste plus assez de lignes à ramener pour atteindre n.

    Néanmoins, ce n'est pas tant le %NOTFOUND en soi qui est un problème, c'est surtout une question de localisation.
    Si on le met après la portion de code qui traite le lot de lignes ramenées, et non juste après le FETCH, ça peut marcher même quand le lot de lignes n'est pas complet (inférieur à n).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    set serveroutput on
    
    declare
    	type num_tab IS TABLE of number INDEX BY pls_integer;
    	n_t num_tab;
     
    cursor c IS
    	SELECT TT.COL1
    	FROM test_table tt;
    
    begin
    	open c;
    	loop
    		fetch c bulk collect INTO n_t LIMIT 10;
    		FOR i IN 1..n_t.count
    		loop 
    			dbms_output.put_line(n_t(i));
    		end loop;
    		exit when c%notfound;
    	end loop;
    	close c;
     end;
     /
    Il n'en reste pas moins que pratiquer ainsi oblige à alourdir le code si on veut traiter aussi les cas limites (table vide).

    Votre test de sortie sur le COUNT de la collection étant simple et universel, il n'y a pas de raison de s'en priver !

    D'ailleurs, il est amusant de voir que Feuerstein pousse le bouchon encore plus loin en recommandant carrément, si j'ai bien compris, de ne plus utiliser le test avec %NOTFOUND dès lors qu'on utilise du BULK COLLECT, et ce avec ou sans LIMIT.
    http://www.oracle.com/technetwork/is...ql-095155.html

Discussions similaires

  1. [String] Probleme incomprehensible avec split
    Par scorpiwolf dans le forum Collection et Stream
    Réponses: 3
    Dernier message: 20/07/2004, 21h21
  2. [JTextAera][JScrollPane]Probleme mineur avec l'ascenseur
    Par Voxdei dans le forum Composants
    Réponses: 2
    Dernier message: 18/07/2004, 09h52
  3. [VB.NET] - Probleme Label avec Database
    Par codez dans le forum ASP.NET
    Réponses: 4
    Dernier message: 03/06/2004, 17h37
  4. probleme sql avec delphi
    Par lil_jam63 dans le forum Bases de données
    Réponses: 7
    Dernier message: 25/02/2004, 04h32
  5. probleme GRAVE avec directx 9
    Par l'arbre en plastique dans le forum DirectX
    Réponses: 3
    Dernier message: 02/09/2003, 23h59

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