Оптимизация обработки строк за курсором в Oracle 11g - PullRequest
1 голос
/ 03 января 2012

Мне нужно обрабатывать большую таблицу (записи по 2,5 Б) построчно, чтобы отслеживать две переменные. Как можно себе представить, это довольно медленно. Я ищу идеи о том, как настроить эту процедуру. Спасибо.

declare
    cursor c_data is select /* +index(data data_pk) */ * from data order by data_id;
    r_data c_data%ROWTYPE;
    lst_b_prc number(15,8);
    lst_a_prc number(15,8);
begin
    open c_data;
    loop
        fetch c_data into r_data;
        exit when c_data%NOTFOUND;

        if r_data.BATS = 'B' then
            lst_b_prc := r_data.PRC;
        end if;
        if r_data.BATS = 'A' then
            lst_a_prc := r_data.PRC;
        end if;
        if r_data.BATS = 'T' then

          insert into trans .... lst_a_prc , lst_b_prc      
           end if;
    end loop;
    close c_data;
end;

Проблема действительно сводится к поиску эффективного sql для отслеживания последнего значения PRC, когда BATS = 'A' и BATS = 'B' для каждой записи BATS = 'T'.

Ответы [ 2 ]

1 голос
/ 07 января 2012

Если я правильно понимаю вашу проблему, с таблицей данных, подобной этой:

create table data as
select 1 data_id, 'T' bats, 1 prc from dual union all
select 2 data_id, 'A' bats, 2 prc from dual union all
select 3 data_id, 'B' bats, 3 prc from dual union all
select 4 data_id, 'T' bats, 4 prc from dual union all
select 5 data_id, 'A' bats, 5 prc from dual union all
select 6 data_id, 'T' bats, 6 prc from dual union all
select 7 data_id, 'B' bats, 7 prc from dual union all
select 8 data_id, 'T' bats, 8 prc from dual union all
select 9 data_id, 'T' bats, 9 prc from dual;

Вы хотите вставить одну строку для каждого T, используя последнее значение PRC для A и B. Что будет выглядеть примерно так:

T data_id   Last A   Last B
---------   ------   ------
1           null     null
4           2        3
6           5        3
8           5        7
9           5        7

Этот запрос должен работать:

select data_id, last_A, last_B
from
(
    select data_id, bats, prc
        ,max(case when bats = 'A' then prc else null end) over
            (order by data_id
             rows between unbounded preceding and current row) last_A
        ,max(case when bats = 'B' then prc else null end) over
            (order by data_id
             rows between unbounded preceding and current row) last_B
    from data
)
where bats = 'T';

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

1 голос
/ 03 января 2012

Есть несколько вариантов. Что наиболее важно, вы, вероятно, ведете огромный журнал UNDO / REDO для всех ваших вставок. Вы можете иногда фиксировать свою работу, скажем, каждые 1000 вставок.

Другой вариант - использовать оператор SQL MERGE (или более простой оператор INSERT .. SELECT ..), который позволит вашему экземпляру Oracle работать с наборами, а не с отдельными записями. План выполнения по вашему выбору может быть оптимизирован для оптимальной INSERT производительности.

...