2010-10-09 5 views
1

J'essaie de copier des enregistrements d'une table à l'autre le plus rapidement possible.Problème de performance avec Oracle BULK FETCH et FORALL insert

Actuellement, j'ai simple similaire boucle de curseur sur ceci:

FOR rec IN source_cursor LOOP 
    INSERT INTO destination (a, b) VALUES (rec.a, rec.b) 
END LOOP; 

Je veux accélérer ce pour être super rapide si je essaie quelques opérations VRAC (un VRAC Fetch, puis un insert FORALL):

Voici ce que j'ai pour l'insert bulk select/forall.

DECLARE 
    TYPE t__event_rows IS TABLE OF _event%ROWTYPE; 
    v__event_rows t__event_rows; 

    CURSOR c__events IS 
    SELECT * FROM _EVENT ORDER BY MESSAGE_ID; 
BEGIN 
    OPEN c__events; 
    LOOP 
    FETCH c__events BULK COLLECT INTO v__event_rows LIMIT 10000; -- limit to 10k to avoid out of memory 

    EXIT WHEN c__events%NOTFOUND; 

    FORALL i IN 1..v__event_rows.COUNT SAVE EXCEPTIONS 
     INSERT INTO destinatoin 
     (col1, col2, a_sequence) 
     VALUES 
     ( v__event_rows(i).col1, v__event_rows(i).col2, SOMESEQEUENCE.NEXTVAL); 


    END LOOP; 
    CLOSE c__events; 


END; 

Mon problème est que je ne vois pas de gros gains de performance jusqu'à présent. D'après ce que je lis, il devrait être 10x-100x plus rapide.

Est-ce qu'il me manque un goulot d'étranglement quelque part?

+1

pour 100 000 lignes, cela prend environ 300 (!) Secondes même avec l'insertion en bloc – Will

+4

Y a-t-il une raison pour laquelle vous avez un ORDER BY dans votre SELECT? Il pourrait être plutôt coûteux de trier 100 000 lignes et cela ne semble pas nécessaire. Votre vérification% NOTFOUND doit également se produire après votre FORALL-- sinon, si vous récupérez moins de 10 000 lignes dans la dernière itération, vous n'insérez pas ces lignes. –

+0

merci! Je vais supprimer la commande par, mais je ne pense pas que cela va me faire tout à fait à la vitesse im la recherche ... je vais essayer d'obtenir une analyse tkprof et mettre à jour ce plus tard. bon attraper avec le% NOTFOUND – Will

Répondre

7

Le seul avantage votre code a plus d'un simple INSERT + SELECT est que vous sauf exceptions, plus (comme le souligne Justin out) vous avez un ORDER BY inutile qui rend faire beaucoup de travail dénué de sens. Vous n'avez alors aucun code pour faire quoi que ce soit avec les exceptions qui ont été enregistrées, de toute façon. Je voudrais simplement l'implémenter comme INSERT + SELECT.

+2

Et vous peut utiliser une clause LOG ERRORS sur l'INSERT pour enregistrer des exceptions. –

0

Vous n'avez pas besoin d'utiliser des boucles inutilement jusqu'à ce que cela soit nécessaire dans le codage lui-même.

+0

Cela devrait être un commentaire, pas une réponse. –

+0

Oui, mais le code nécessite quelques conseils pour de meilleurs problèmes de performance. –

+0

Oui, c'est pourquoi ça devrait être un commentaire :) –