cursor for loop vs. bulk collect forall

publikováno: 4.1.2016

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;

Reference

Kurz SQL byl jedním slovem výborný. Připravená smysluplná databáze spolu s příklady, včetně příkladů s vysokou obtížností - je tak možné dostatečně zabavit i pokročilejší studenty. Za pozitivní považuji opravdu

Michal

SQL i PL/SQL jsem znal už před kurzem, ale příklady a vysvětení mi pomohlo trošku lépe pochopit, jak to funguje. Navíc i přesto, že jsem už s SQL a MySQL

Lukáš

týdenní školení proběhlo podle našich očekávání, super přístup i poskytnuté informace o PL/SQL

Nicole


Novinky

3.1.2018: Oracle XE 12c nebude, místo toho bude Oracle XE 18c
V roce 2018 nás čeká nová XE verze a nové verzování

4.4.2017: SAP HANA & Veverka (SQuirrel SQL)
Oficiální SAP HANA studio funguje, ale je hrozně pomalé. Další z nástrojů, kde je možné rozchodit SAP HANA je Veverka (SQuirrel SQL)

25.3.2017: SAP HANA referenční příručky
V současnosti je trošku složitější najít na webu referenční příručku k SAP HANA SQL, proto sem dávám odkazy.