Оптимизация запросов для обновления миллионов данных в Oracle? - PullRequest
0 голосов
/ 16 января 2019

У меня есть 3 таблицы:

  • Таблица A: 170 миллионов данных
  • Таблица B: 170 миллионов данных
  • Таблица C: 130 миллионов данных
  • Таблица журнала

Я хочу обновить столбец colA1 со значением colC4 , если colA2 == colB2 и colB3 == colC3 . Я создал таблицу:

  • Таблица D: 80 миллионов данных для хранения colB2 и colC3 для ускорения запроса.

Я также добавляю индекс для colB3 в Таблицу D.

Таблица журнала используется для хранения сообщения о ходе выполнения и времени завершения при каждом завершении итерации (см. Сценарий).

В настоящее время мой скрипт обновления выглядит так:

v_str_log := 'Begin updating';
p_write_to_log(v_str_log);
commit;

for data_list in
(
    select distinct colC4
    from tableC
)
loop
    update tableA
    set colA1 = data_list.colC4
    where colA2 in
    (
        select colB2
        from tableD
        where colC3 = data_list.colC4
    )
    var_total := var_total + sql%rowcount;
    v_str_log := 'Updated ' || sql%rowcount || ' for ' || card.sim_type || ' with total ' || var_total || ' rows.';
    commit;
end loop;

Я запустил процедуру, и она закончилась примерно через 6 часов. Но из журнала я нахожу, что для первого цикла 3 миллиона данных выполняются за 3 минуты, а спустя несколько итераций 5 миллионов данных выполняются примерно за 20 минут. Запрос выполняется не так быстро, как первые итерации

Почему это могло случиться? Можно ли оптимизировать скрипт?

1 Ответ

0 голосов
/ 16 января 2019

Вам нужно взглянуть на Возможность обновления с возможностью объединения в Oracle - это как раз ваш вариант использования.

Сначала объедините все таблицы в подзапросе (это будет эффективно выполнено с помощью хеш-объединения без медленных циклов строк за строкой).

Чем UPDATE подзапрос

Пример

create table a
(col1 number,
col2 number);

create table b
(col2 number,
col3 number);

create table c
(col3 number,
col4 number);

insert into a values(null,1);
insert into b values(1,2);
insert into c values(2,1);


update (
select a.col1, c.col4
from a 
join b on a.col2 = b.col2
join c on b.col3 = c.col3
)
set col1 = col4
;

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

ORA-01779: невозможно изменить столбец, который сопоставляется с таблицей без сохранения ключа

В вашем случае вы должны подкрепить таблицу B и C уникальным индексом, чтобы гарантировать представление сохранения ключа

create unique index c_idx on c(col3);
create unique index b_idx on b(col2);

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

...