Sim, muitas pessoas estão seguindo uma má prática.
Estilo Ruim
Eu concordo com @Osy que OPEN/FETCH/CLOSE adiciona código completamente desnecessário. Eu iria ainda mais longe e diria que você quase nunca deve usar
CURSOR
. Em primeiro lugar, você normalmente quer fazer o máximo possível em SQL simples. Se você precisar usar PL/SQL, use um cursor implícito. Isso economizará uma linha de código e ajudará você a manter a lógica relacionada mais próxima.
Acredito firmemente em manter as unidades individuais de código tão pequenas quanto possível. À primeira vista, parece um
CURSOR
pode ajudá-lo a fazer isso. Você pode definir seu SQL no topo em um só lugar e, em seguida, fazer o loop PL/SQL posteriormente. Mas, na realidade, essa camada extra de indireção quase nunca vale a pena. Às vezes, muita lógica está em SQL e, às vezes, muita lógica está em PL/SQL. Mas, na prática, raramente faz sentido colocar muita lógica complexa em ambos. Seu código geralmente acaba se parecendo com um destes:
for records in (<simple SQL>) loop
<complex PL/SQL>
end loop;
ou:
for records in
(
<complex SQL>
) loop
<simple PL/SQL>;
end loop;
De qualquer forma, uma de suas seções de código será muito pequena. A complexidade de separar essas duas seções de código é maior do que a complexidade de uma única seção de código maior. (Mas essa é obviamente a minha opinião.)
Desempenho ruim
Existem implicações de desempenho significativas com o uso de OPEN/FETCH/CLOSE. Esse método é muito mais lento do que usar um cursor para loop ou um cursor implícito.
O compilador pode usar automaticamente a coleta em massa em alguns loops for. Mas, para citar a apresentação da Oracle "Desempenho de PL/SQL — desmistificando os mitos" , página 122:
Aqui está um exemplo rápido:
--Sample data
create table t(a number, b number);
insert into t select level, level from dual connect by level <= 100000;
commit;
--OPEN/FETCH/CLOSE
--1.5 seconds
declare
cursor test_cur is
select a, b from t;
test_rec test_cur%rowtype;
counter number;
begin
open test_cur;
loop
fetch test_cur into test_rec;
exit when test_cur%notfound;
counter := counter + 1;
end loop;
close test_cur;
end;
/
--Implicit cursor
--0.2 seconds
declare
counter number;
begin
for test_rec in (select a, b from t) loop
counter := counter + 1;
end loop;
end;
/