I "gamle" dage, dvs. siden version 7, var det helt normalt at vi hentede vores data række-for-række, i et FOR loop, eller et WHILE loop, ved brug af PL/SQL. Så kom Oracle 8i på gaden, og introducerede nogen helt nye ting, hvor vi indenfra PL/SQL, kunne benytte nogen features, for at arbejde med data i array's dvs. istedet for række-for-række princippet, kunne vi behandle flere rækker ved en læsning. Disse nye features var; BULK COLLECT samt FORALL.

  1. BULK COLLECT betyder, hentning af flere rækker på en gang. 
  2. FORALL forbedrer performance af INSERT, UPDATE, and DELETE (DML) udtryk.

Oracle databasen fik mærkbare forbedringer mht. performance, ved brug af disse 2 nye udtryk, bl.a. reduceredes antallet af context switches mellem PL/SQL og SQL udtryks eksekverings mekanismerne.

Det betyder at PL/SQL eksekveres af PL/SQL "maskinen" og SQL indeholdt i PL/SQL eksekveres af SQL "makinen", så der er en konstant dialog mellem de to mekanismer, når din kode eksekveres, deraf disse context switches.

BULK COLLECT dine data

Siden version 8i, til idag er der sket en del forbedringer med BULK COLLECT. Bulk Collect henter flere rækker ind ved brug, i en eller flere collections. En ny feature ved Bulk collect er bulk binding. Istedet for at overføre rækker 1-by-1 mellem SQL og PLSQL "maskinen" - kan man ved brug af Bulk binding, overføre collections. Det har bl.a. den fordel, at antal context switches nedsættes og performance øges.

Bulk binding er tilgængelig for select, insert, delete og update udtryk.

Normalt når jeg udvikler, benytter jeg enten et FOR loop (så slipper jeg for at åbne, fetche, og lukke cursoren), eller opretter en CURSOR, åbner cusoren, FECTH INTO min cursor, og lukker cursoren. Gældende er jeg ved hentning af data, henter række-for-række.

Lad mig give et eksempel på brug af BULK COLLECT;

SQL> create table t_Turbo as select * from customer;

Table created.

SQL> select count(*) from t_Turbo;

COUNT(*)
----------
219856

SQL> declare
2 cursor cursor1 is select object_name from t_Turbo;
3 record1 cursor1%rowtype;
4  begin
5  open cursor1;
6  loop
7     fetch cursor1 into record1;
8     exit when cursor1%notfound;
9
10     null;
11
12  end loop;
13  end;
14  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:33.25

SQL> declare
2  cursor cursor1 is select object_name from t_Turbo;
3  type cursor1_type is table of cursor1%rowtype;
4  record1 cursor1_type;
5  begin
6  open cursor1;
7
8     fetch cursor1 bulk collect into record1;
9
10
11  end;
12  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:06.32

Nu var det en rimelig stor tabel, men som du ser har BULK COLLECT, en ret stor effekt.Du skal dog være opmærksom jo flere data, jo flere BULK COLLECTS der kører på samme tid, dets større bliver din process memory. Det siger næsten sig selv, men vær opmærksom på det. Alternativt kan BULK COLLECT begrænses vha. LIMIT.

SQL> declare
2  cursor cursor1 is select object_name from t_Turbo;
3  type cursor1_type is table of cursor1%rowtype;
4  record1 cursor1_type;
5  begin
6  open cursor1;
7  loop
8     fetch cursor1 bulk collect into record1 limit 200;
9     for i in 1..record1.count loop
10             null;
11     end loop;
12     exit when cursor1%notfound;
13  end loop;
14
15
16  end;
17  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:01.07

Turbocharged DML ved brug af FORALL

FORALL overfører data fra en PL/SQL collection til tabeller der benytter collections.

Uden af skulle gentage FORALL henviser jeg til en artikle skrevet af Steven Feuerstein, i Oracle Magazine, hvor du finder en virkelig god gennemgang af FORALL, incl. alle de nye 10G features. God fornøjelse.