2016-05-20 3 views
0

Мне нужно обработать около 60 тыс. Записей таблицы Oracle через хранимую процедуру. Обработка состоит в том, что для каждой такой строки мне нужно удалить и обновить строку во второй таблице и вставить строку в третью таблицу.Oracle Bulk Collect with Limit и для всех не обрабатывает все записи правильно

Используя цикл курсора, процедура занимает около 6-8 часов. Если я переключусь на Bulk Collect with Limit, время выполнения сократится, но обработка будет неправильной. Ниже приводится основная часть сбора версия процедуры

create or replace procedure myproc() 
is 
    cursor c1 is select col1,col2,col3 from tab1 where col4=3; 
    type t1 is table of c1%rowtype; 
    v_t1 t1; 
begin 
    open c1; 
    loop 
     fetch c1 bulk collect into v_t1 limit 1000; 
     exit when v_t1.count=0; 
     forall i in 1..v_t1.count 
      delete from tab2 where tab2.col1=v_t1(i).col1; 
     commit; 
     forall i in 1..v_t1.count 
      update tab2 set tab2.col1=v_t1(i).col1 where tab2.col2=v_t1(i).col2; 
     commit; 
     forall i in 1..v_t1.count 
      insert into tab3 values(v_t1(i).col1,v_t1(i).col2,v_t1(i).col3); 
     commit; 
    end loop; 
    close c2; 
end; 

Для около 20k этих записей, первая операция удаления правильно обработан, но последующее обновление и вставка не обрабатывается. Для остальных 40 тыс. Записей все три операции обрабатываются правильно.

Я что-то упустил? Также каково максимальное значение LIMIT, которое я могу использовать с Bulk Collect?

+0

Таким образом, вы знаете, что вы перебрать основной цикл в 60 раз, и вы знаете, что вы делаете 60k удалений, но 40k обновления и вставки? Как вы проверяете/считаете? –

+0

Таблица tab3 - это таблица журналов, которая очищается до выполнения процедуры; поэтому, если после этой процедуры в этой таблице записано 40 тыс. записей, это означает, что вставки 40k были успешными. Таблица (tab1) имеет близкую к 2 * 60k записей до выполнения процедуры и после выполнения, количество записей составляет 60k, что означает, что удаленные 60k были успешными. –

+0

ОК, так что tab2.col1 уникален? Я не пытаюсь быть трудным, просто пытаюсь подумать, что бы вы упустили. –

ответ

0

Вы должны попробовать использовать SAVE EXCEPTIONS положение о FORALL, что-то вроде (непроверенные):

create or replace procedure myproc 
as 
    cursor c1 is select col1,col2,col3 from tab1 where col4=3; 
    type t1 is table of c1%rowtype; 
    v_t1 t1; 
    dml_errors EXCEPTION; 
    PRAGMA exception_init(dml_errors, -24381); 
    l_errors number; 
    l_errno number; 
    l_msg varchar2(4000); 
    l_idx number; 
begin 
    open c1; 
    loop 
     fetch c1 bulk collect into v_t1 limit 1000; 
     -- process v_t1 data 
     BEGIN 
      forall i in 1..v_t1.count SAVE EXCEPTIONS 
       delete from tab2 where tab2.col1=v_t1(i).col1; 
      commit; 
     EXCEPTION 
      when DML_ERRORS then 
       l_errors := sql%bulk_exceptions.count; 
       for i in 1 .. l_errors 
       loop 
        l_errno := sql%bulk_exceptions(i).error_code; 
        l_msg := sqlerrm(-l_errno); 
        l_idx := sql%bulk_exceptions(i).error_index; 
        -- log these to a table maybe, or just output 
       end loop; 
     END; 

     exit when c1%notfound; 
    end loop; 
    close c2; 
end; 
+1

Итак, вы хотите сказать, что эти 20k-записи не обрабатываются без какого-либо исключения, которые мне нужно поймать и log/print для отладки проблемы? Но если действительно есть исключение, не должно ли Жаба (где я выполняю хранимую процедуру) дать мне сообщение и резко прекратить выполнение? –

+0

Нет, я просто говорю, что это полезно при попытке отладки, что происходит. У нас нет конкретных данных, поэтому мы немного догадываемся. Кроме того, возможно, что вы не обновляете или вставляете столько строк, сколько вы думаете, не обязательно, что операция не выполняется (она может запускать инструкцию и вставлять или обновлять 0 строк). Чтобы это знать, вы должны добавить SQL% ROWCOUNT сразу после каждого оператора forall. – tbone

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