Všude čtu jak je BULK-COLLECT výkonný, tak jsem se rozhodl to změřit. Mám data v jedné tabulce a potřebuji některé z nich získat a uložit je do druhé tabulky.
Vstupní data:
-- 1. create table create table test_bulk_source (num number); create table test_bulk_target (num number); -- 2. insert test data declare maximum integer := 1000000; begin FOR i IN 1..maximum LOOP insert into test_bulk_source values (dbms_random.random); END LOOP; commit; end;
Mimochodem: nejjednodušší je udělat toto a vyprdnout se na cokoli složitějšího:
-- 3A. copy data using insert ... select statement -- (operation took on my computer 0,3 seconds!!!) declare time_start number; begin execute immediate 'truncate table test_bulk_target'; time_start := dbms_utility.get_time(); insert into test_bulk_target select num from test_bulk_source where num > 500000; commit; dbms_output.put_line('operation took: ' || (dbms_utility.get_time() - time_start) / 100 || ' seconds'); end;
Kdybychom ale potřebovali se záznamem udělat nějakou operaci, kterou v jednom SELECTu nezvládneme, pak bychom to mohli napsat takto:
-- 3B. copy data using for-loop -- (operation took on my computer 30 seconds!!!) declare time_start number; begin execute immediate 'truncate table test_bulk_target'; time_start := dbms_utility.get_time(); for num_rec in (select num from test_bulk_source where num > 500000) loop insert into test_bulk_target values (num_rec.num); end loop; commit; dbms_output.put_line('operation took: ' || (dbms_utility.get_time() - time_start) / 100 || ' seconds'); end;
Ale skutečně výkonné řešení je toto:
-- 3C. copy data using bulk-collect-forall -- (operation took on my computer 0,5 seconds!!!) declare time_start number; cursor c is select num from test_bulk_source where num > 500000; type number_collection is table of number; numbers number_collection; begin execute immediate 'truncate table test_bulk_target'; time_start := dbms_utility.get_time(); open c; fetch c bulk collect into numbers; forall i in numbers.first .. numbers.last insert into test_bulk_target values(numbers(i)); close c; commit; dbms_output.put_line('operation took: ' || (dbms_utility.get_time() - time_start) / 100 || ' seconds'); end;
Školení bych doporučil všem lidem, kteří se chtějí dozvědět něco o DB. Na školeni jsem přišel, jako úplný nováček, co se týče práci s DB a odcházel plný dojmů a
Osobně jsem trošku stále váhající, jestli a jak moc SQL použít. Ale určitě hlavní je to, že se teď už tolik nebojím. Je to pro mě začátek dlouhé cesty. Osobně
Zajímavé školení, které vhodně kombinovalo teorii a praxi.