Оптимизация процедуры Oracle 11g - PullRequest
2 голосов
/ 30 декабря 2011

У меня есть процедура, чтобы найти первую, последнюю, максимальную и минимальную цены для серии транзакций в очень большой таблице, которая организована по дате, имени объекта и коду. Мне также нужна сумма произведенных сумм. В таблице около 3 миллиардов строк, и эта процедура занимает много дней. Я хотел бы сократить это время как можно больше. У меня есть индекс по отдельным полям в таблице trans, и, глядя на план объяснения для выбранной части запросов, индекс используется. Я открыт для предложений по альтернативному подходу. Я использую Oracle 11g R2. Спасибо.

    declare
    cursor c_iter is select distinct dt, obj, cd from trans;
    r_iter c_iter%ROWTYPE;
    v_fir number(15,8);
    v_las number(15,8);
    v_max number(15,8);
    v_min number(15,8);
    v_tot number;
    begin
    open c_iter;
    loop
        fetch c_iter into r_iter;
        exit when c_iter%NOTFOUND;

      select max(fir), max(las) into v_fir, v_las 
      from 
            ( select 
                first_value(prc) over (order by seq) as "FIR",
                first_value(prc) over (order by seq desc) as "LAS"
              from trans
              where dt = r_iter.DT and obj = r_iter.OBJ and cd = r_iter.CD );

            select max(prc), min(prc), sum(qty) into v_max, v_min, v_tot
            from trans
            where dt = r_iter.DT and obj = r_iter.OBJ and cd = r_iter.CD;

            insert into stats (obj, dt, cd, fir, las, max, min, tot )
            values (r_iter.OBJ, r_iter.DT, r_iter.CD, v_fir, v_las, v_max, v_min, v_tot);

            commit;
    end loop;
    close c_iter;
end;

Ответы [ 3 ]

7 голосов
/ 30 декабря 2011
alter session enable parallel dml;

insert /*+ append parallel(stats)*/
into stats(obj, dt, cd, fir, las, max, min, tot)
select /*+ parallel(trans) */ obj, dt, cd
    ,max(prc) keep (dense_rank first order by seq) fir
    ,max(prc) keep (dense_rank first order by seq desc) las
    ,max(prc) max, min(prc) min, sum(qty) tot
from trans
group by obj, dt, cd;

commit;
  • Один оператор SQL обычно значительно быстрее, чем несколько операторов SQL.Иногда им требуется больше ресурсов, например, больше временного табличного пространства, но ваш отдельный курсор, вероятно, уже все равно сортирует всю таблицу на диске.
  • Возможно, вы также захотите включить параллельный DML и параллельный запрос, хотя это зависит от вашего объекта иСистемные настройки это может уже происходить.(И это не обязательно хорошо, в зависимости от ваших ресурсов, но обычно это помогает при больших запросах.)
  • Параллельная запись и APPEND должны повысить производительность, если SQL пишет много данных, но это также означает, чточто новая таблица не будет восстановлена ​​до следующего резервного копирования.(Параллельный DML будет автоматически использовать прямую запись пути, но я обычно все равно включаю APPEND на тот случай, если параллелизм не будет работать правильно.)

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

2 голосов
/ 30 декабря 2011

Не точный ответ, который я хотел бы дать, но несколько вещей, на которые следует обратить внимание:

Первый - использование массового сбора .Однако, поскольку вы используете 11g, надеюсь, это уже выполняется автоматически.

Вам действительно нужно фиксировать после каждой итерации?Я могу ошибаться, но я предполагаю, что это один из ваших лучших потребителей времени.

Наконец, +1 за ответ Джонарла.(Я не был уверен, смогу ли я записать все в один SQL-запрос, но я собирался также это предложить.)

0 голосов
/ 30 декабря 2011

Вы можете попытаться выполнить запрос параллельно, для этого есть здесь .Это не та особенность Oracle, которую мне когда-либо приходилось использовать самому, так что у меня нет непосредственного опыта ее передачи.Вам также необходимо иметь достаточно свободных ресурсов на сервере Oracle, чтобы можно было запускать параллельные процессы, которые будут созданы.

...