Monday, March 12, 2007
Bulk Collect
Meu mantra para performance é:
Vamos ao teste, que consiste em comparar o tratamento de um mesmo cursor de duas maneiras - uma, linha a linha e outra com bulk collect. Também há uma subrotina na procedure que mostra o tempo tomado em cada execução. A lógica é alterar a coluna object_name para initcap(object_name). Apenas para fixar conceito: Qual seria o melhor forma de tratar essa modificação? ...
Muito bem! Opção 1 - SQL Puro, bastaria
- SQL Puro - Me esforço o máximo para usar SQL Puro.
- PL/SQL - Quando a lógica é complexa.
- External C procs - Para ser sincero, faz algum tempo que não utilizo.
Vamos ao teste, que consiste em comparar o tratamento de um mesmo cursor de duas maneiras - uma, linha a linha e outra com bulk collect. Também há uma subrotina na procedure que mostra o tempo tomado em cada execução. A lógica é alterar a coluna object_name para initcap(object_name). Apenas para fixar conceito: Qual seria o melhor forma de tratar essa modificação? ...
Muito bem! Opção 1 - SQL Puro, bastaria
insert into gtt select initcap(object_name) from t;Entretanto, estamos estudando a melhor forma de tratar um cursor. A seguir a lógica do teste.
- Cursor abre, le a tabela "T" linha a linha, faz a modificação (initcap) e insere na tabela "GTT".
- Mostra tempo de execução 'Tempo cursor normal'
- Cursor abre, le a tabela "T" de 100 em 100 registros e monta um set (type - array), faz a modificação (initcap) e insere os 100 registros na tabela "GTT" volta ao item 3 até completar a tabela "T".
- Mostra tempo de execução 'Tempo bulk collect'
- Fim.
ops$marcio:LX10G> create table t as select * from all_objects;O tempo é indiscutível. Aproximadamente 3 vezes mais rápido! Para cerca de 50 mil linhas.
Table created.
ops$marcio:LX10G> create global temporary table gtt on commit preserve rows
2 as select * from t where 1=0;
Table created.
ops$marcio:LX10G>
ops$marcio:LX10G> create or replace procedure p
2 is
3 cursor c is select * from t;
4 type rec is table of c%rowtype index by binary_integer;
5 l_rec rec;
6 l_time number default dbms_utility.get_time;
7 procedure show_time (p_message in varchar2) is
8 begin
9 dbms_output.put_line(p_message ||
10 trunc((dbms_utility.get_time - l_time)/100,2) || ' segundos!');
11 l_time := dbms_utility.get_time;
12 end;
13 begin
14 execute immediate ('truncate table gtt');
15 for x in c
16 loop
17 x.object_name := initcap(x.object_name);
18 insert into gtt values x;
19 end loop;
20 show_time('Tempo cursor normal ');
21 execute immediate ('truncate table gtt');
22 open c;
23 loop
24 fetch c bulk collect into l_rec limit 100;
25
26 for i in 1 .. l_rec.count
27 loop
28 l_rec(i).object_name := initcap(l_rec(i).object_name);
29 end loop;
30
31 forall i in 1 .. l_rec.count
32 insert into gtt values l_rec(i);
33
34 exit when c%notfound;
35 end loop;
36 close c;
37 show_time('Tempo bulk collect ');
38 end;
39 /
Procedure created.
ops$marcio:LX10G> show error;
No errors.
ops$marcio:LX10G>
ops$marcio:LX10G> exec p;
Tempo cursor normal 3,05 segundos!
Tempo bulk collect ,45 segundos!
PL/SQL procedure successfully completed.
ops$marcio:LX10G>
Labels: Performance
Comments:
<< Home
Inicialmente belo post, muito interessante. Sem sombra de dúvidas o uso do bulk collect melhora muito o desempenho, no entanto ouvi em alguns lugares que ele consome muita memória, visto que cada sessão partilha de uma área comum da memória.
Pode ocorrer em algum caso de se ter problemas de memória?
Post a Comment
Pode ocorrer em algum caso de se ter problemas de memória?
<< Home