2012-06-01 8 views
0

Мне нужно сделать некоторые вставки в курсоре более 300000 строк, но это работает медленно, любые идеи о том, как я могу заставить его работать быстрее? Могу ли я ускорить его, выполнив коммиты? Так, например, я бы выполнил фиксацию после 1000-й строкиЛучшая практика для выполнения вставок в курсоре

DECLARE 

    CURSOR test_cursor IS 
    SELECT a from database.mytable 
BEGIN 

    FOR curRow IN test_cursor LOOP 

    insert into tableb (testval) 
    values ('something'); 

    commit; 

    END LOOP; 
END; 

ответ

0

Я бы не рекомендовал подход курсора для этого. Я использую вспомогательные параллельные подсказки для ситуаций, подобных этому. В большинстве случаев ваш запрос буквально выполняет N раз быстрее, когда N является параллельной степенью. Иногда бывает хорошей идеей обходить аварийное восстановление с помощью nologging/noarchivelog.

Для действительно больших миграций (от десятков до сотен ГБ), я нашел, что это хорошая идея для партии на естественном ключе таблицы (дата, обычно). Некоторое небольшое количество состояний вокруг него может позволить вам отменить + возобновить миграцию по желанию, если необходимо.

-1

Может быть, это поможет вам, пожалуйста, попробуйте этот

DECLARE 
i number; 
    CURSOR test_cursor IS 
    SELECT a from database.mytable 
BEGIN 

    FOR curRow IN test_cursor LOOP 

    insert into tableb (testval) 
    values ('something'); 
i:i+1; 
if mod(i,1000)=0 then 
    commit; 
end if; 
    END LOOP; 
commit; 
END; 
+0

-1 Не атакует основную причину, уменьшает количество коммитов вместо того, чтобы полностью избавиться от коммитов, и, прежде всего: этот код не проверен и не работает так, как вы планировали. –

3

Или вы можете попробовать это:

DECLARE 
    CURSOR test_cursor IS 
    SELECT col1 from table_a; 

    TYPE fetch_array IS TABLE OF test_cursor%ROWTYPE; 
    test_array fetch_array; 

    l_errors        PLS_INTEGER; 
    l_dml_errors       EXCEPTION; 
    PRAGMA EXCEPTION_INIT(l_dml_errors, -24381);  

BEGIN 

    open test_cursor; 
    loop 
    fetch test_cursor bulk collect into test_array limit 10000; 
    forall i in 1..test_array.count save exceptions 
     insert into table_b(col1) 
     values(test_array(i).col1); 
     exit when test_cursor%notfound; 
    end loop; 
    close test_cursor; 
    commit; 

EXCEPTION 
WHEN l_dml_errors THEN 
    l_errors := SQL%BULK_EXCEPTIONS.COUNT; 
    dbms_output.put_line('Number of INSERT statements that failed: ' || l_errors); 
    FOR i IN 1 .. l_errors 
    LOOP 
     dbms_output.put_line('Error #' || i || ' at '|| 'iteration #' || SQL%BULK_EXCEPTIONS(i).ERROR_INDEX); 
     dbms_output.put_line('Error message is ' || SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE)); 
    END LOOP; 
END; 
+0

Я предпочитаю три строки ответа Винсента ... –

+0

Будьте осторожны с коллекциями. Несколько недель назад я сражался с утечками памяти на нашем 10.2.0.3, которые были вызваны такими массовыми операциями. Мы выяснили, что это была ошибка, которая должна быть исправлена ​​в 10.2.0.4. – ipip

8

300000 строк не так много строк. Если строки не равны чрезвычайно больших, вы не должны совершать в середине партии.

Intermediate совершает will only achieve:

  • дополнительные накладные расходы, поскольку при каждой фиксации создает дополнительную работу,
  • потеря возможности перезапуска в случае ошибки (и потери целостности транзакций),
  • больше шансов нарваться ORA -1555

Если ваш процесс действительно является курсором с одной вставкой внутри цикла, вы должны запустить один оператор:

BEGIN 
    INSERT INTO tableb (col1..coln) (SELECT col1..coln FROM database.mytable); 
END; 

Если вы все еще нуждаетесь в дополнительной производительности, вы можете посмотреть в прямые вставки и параллельную работу, но это может быть сверхоптимизации с «только» 300k строк.

На сегодняшний день единственной наибольшей оптимизацией, доступной вам, является думать в терминах множеств вместо традиционного процедурного подхода, который состоит из партий однострочных операторов.

+0

+1 Для того, чтобы не совершать внутри цикла, почти во всех случаях это плохая идея. – Wolf

Смежные вопросы