Должен ли я очищать коллекции каждый выбор l oop для использования в forall? PL SQL Oracle - PullRequest
0 голосов
/ 12 апреля 2020

Допустим, у меня есть огромные данные (строки 100k-1m) в таблице 1, которые мне нужно сделать некоторую проверку, а затем обновить их состояние в таблице 2 на основе отфильтрованных результатов. Как вы можете видеть с моим упрощенным кодом. Я массово собираю 1000 строк в пакете и фильтрую их в 3 разные коллекции (dsa1, dsa2, dsa3), а затем позже обновлю эти 3 коллекции в table2.

Моя проблема заключается в том, что первая выборка получает 100 строк в dsa1, тогда вторая выборка получает только 70 строк в dsa1. Когда выполняется полное обновление, оно также обновляет старые 30 строк в dsa1 с первой выборки.

2 Решения, о которых я думаю, это первое: удалить все элементы в коллекциях при каждой выборке l oop. и второе - поместить вывод за пределы выборки l oop, что сделает 3 набора очень большими, но вызов вызывается только один раз.

Второе решение будет занимать много памяти, верно? посоветуйте пожалуйста какие лучшие решения

declare

cursor c1 is 
select t1.id, t1.status, t2.con from table1 t1, table2 t2
where t1.id = t2.id;

type ty_c1 is table of c1%rowtype;
asd1 ty_c1 := ty_c1();

type ty_id is table of c1.id%type index by pls_integer;
dsa1 ty_id;
dsa2 ty_id;
dsa3 ty_id;
begin
    open c1;
    loop
        fetch c1 bulk collect into asd1 limit 1000;
        exit when asd1.count = 0;

        for i in 1 .. asd1.count
        loop
            if (asd1(i).status = 'ACT') then
                dsa1(i).id := asd1(i).id;
            elsif (asd1(i).status = 'NOT ACT') then
                dsa2(i).id := asd1(i).id;
            else
                dsa3(i).id := asd1(i).id;
            end if;
        end loop;

        forall idx in indices of dsa1
            update table2 set con = 'ACTIVE'
            where id = dsa1(idx).id;

        forall idx in indices of dsa2
            update table2 set con = 'NOT ACTIVE'
            where id = dsa2(idx).id;

        forall idx in indices of dsa3
            update table2 set con = 'DEAD'
            where id = dsa3(idx).id;


    end loop;
    close c1;
end;

1 Ответ

0 голосов
/ 12 апреля 2020

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

Таким образом, ответ зависит от типичного объема, который вы будете обрабатывать, и доступной памяти. .

Вы также можете иметь четвертую коллекцию, которая остается пустой, и назначить пустую коллекцию dsa1, dsa2 и dsa3 в l oop вместо удаления записей.

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

И еще один шаг, поскольку 1M записей - это ничто для базы данных oracle (миллиарды записей огромны, миллион записей тривиальны), просто используйте базу данных для выполнения одного оператора select update

update table2 t2
set conn=(select decode(t1.status, 'ACT', 'ACTIVE', 'NOT ACT','NON ACTIVE','DEAD') 
from table1 t1)
where t2.id=t1.id

NB строк в t2, которые не существуют в t1, будут иметь conn se т до нуля, но вы можете ограничить, где пункты, чтобы ограничить влияние, если это не желательно.

вы также можете добавить параллельный совет как для обновления, так и для выбора, чтобы использовать больше процессоров, и если вы можете изменить Модель данных, использующая код цифры c вместо varchar для представления статуса, также будет более эффективной.

...