2012-12-04 3 views
1

Je suis en train de développer une procédure stockée pour Oracle 10g et je suis en train de mettre en place un encombrement assez important en essayant de passer une liste de 2 à 3k éléments. Voici mon code:Performances Oracle INSERT pour de gros blocs de données

TYPE ty_id_list 
    AS TABLE OF NUMBER(11); 

---------------------------------------------------------- 


PROCEDURE sp_performance_test (
    p_idsCollection IN schema.ty_id_list) 
AS 

TYPE type_numeric_table IS TABLE OF NUMBER(11) INDEX BY BINARY_INTEGER; 
l_ids type_numeric_table; 
data type_numeric_table; 
empty type_numeric_table; 

BEGIN 

EXECUTE IMMEDIATE 
    'ALTER TABLE schema.T_TEST_TABLE NOLOGGING'; 
COMMIT; 

SELECT COLUMN_VALUE BULK COLLECT INTO l_ids 
    FROM TABLE(p_idsCollection); 

FOR j IN 1 .. l_ids.COUNT LOOP 
    data(data.count+1) := l_ids(j); 

    IF(MOD(data.COUNT,500) = 0) THEN 
    FORALL i IN 1 .. data.COUNT 
     INSERT INTO schema.T_TEST_TABLE (REF_ID, ACTIVE) 
     VALUES (data(i), 'Y'); 
    data := empty; 
    END IF; 
END LOOP; 
IF(data.count IS NOT NULL) THEN 
    FORALL i IN 1 .. data.COUNT 
    INSERT INTO schema.T_TEST_TABLE (REF_ID, ACTIVE) 
    VALUES (data(i), 'Y'); 
END IF; 
COMMIT; 

EXECUTE IMMEDIATE 
    'ALTER TABLE schema.T_TEST_TABLE LOGGING'; 
COMMIT; 

END sp_performance_test; 

Donc, la chose qui ajoute au processus semble tout à fait être radicalement cette partie: les données (data.count + 1): = l_ids (j); Si j'ignore d'obtenir l'élément de la collection et remplace cette ligne par data (data.count + 1): = j;, le temps d'exécution de la procédure sera 3-4 fois plus rapide (de plus de 30s à 8-9s pour 3k éléments) - mais cette logique n'est évidemment pas celle que je veux. Pouvez-vous me donner un indice où pourrais-je améliorer mon code pour obtenir de meilleures performances lors de l'insertion de données? Si des améliorations peuvent être faites vraiment.

Merci, Przemek

+1

Votre procédure ne prend que 0,7 secondes pour moi, en utilisant les valeurs 3K sur un vieux PC de bureau. Et la plupart de ce temps est passé à analyser mes données d'échantillon. Cela implique soit que votre serveur est très lent, soit qu'il y a d'autres conditions spéciales qui prennent le plus de temps. Pouvez-vous ajouter la table DDL et un script pour générer des exemples de données? Peut-être n'avez-vous pas besoin d'optimiser cette procédure, peut-être que le problème est ailleurs. Par exemple, il y a peut-être un déclencheur qui ralentit les inserts. –

Répondre

0

Je ne suis pas votre logique.

Vous acceptez une collection. Vous copiez à une autre collection:

SELECT COLUMN_VALUE BULK COLLECT INTO l_ids 
    FROM TABLE(p_idsCollection); 

Et puis vous copiez une fois de plus, dans une boucle:

FOR j IN 1 .. l_ids.COUNT LOOP 
    data(data.count+1) := l_ids(j); 

Et seulement après que vous parvenez à effectuer vos 500 rangs chunk insert en vrac. Quel est le problème avec l'insertion en vrac immédiatement p_idsCollection?

p.s. Vous n'avez pas besoin de commits après 'ALTER TABLE', les instructions ddl les émettent implicitement.

+0

Bonjour, désolé pour la confusion, la seule raison pour laquelle j'ai fait réécrire la collection de p_idsCollection à l_ids est de (potentiellement) profiter de l'indexation de type_numeric_table, je ne suis pas entièrement sûr si cela fait beaucoup de sens mais finalement cette opération n'ajoute pas grand-chose aux temps d'exécution du processus. Le découpage en morceaux de 500 rangs ne fait que suivre les conseils d'Oracle «Ask Tom» et semble accélérer l'insertion d'un LOT comparant juste la boucle FORALL à la collection originale complète. – pmacialek

+0

vous ne prenez aucun avantage ici. ce n'est pas une "table indexée", c'est un tableau associatif. consultez la section doc correspondante: http://docs.oracle.com/cd/B19306_01/appdev.102/b14261/collections.htm # i20383 –

+0

Merci pour cette prise, bon à savoir! Mais cela n'aide pas beaucoup avec ma performance globale malheureusement. – pmacialek

0

ce bloc entier après la LDD peut être réécrite comme

insert into schema.T_TEST_TABLE (REF_ID, ACTIVE) 
select COLUMN_VALUE, 'Y' FROM TABLE(p_idsCollection); 
+0

Ouais essayé cela comme une des premières tentatives, mais les performances de INSERT-SELECT semble être légèrement plus lent que celui de mon dernier code (split FORALL). Merci de répondre! – pmacialek

0

Vous pouvez également ajouter en touche opération d'insertion.

Insérer/* + ajouter */dans l'onglet (...) les valeurs (...)

Il oracle de changement de logique de travail et il va fonctionner plus rapidement.

http://www.dba-oracle.com/t_insert_tuning.htm

Questions connexes