Sì, molte persone stanno seguendo una cattiva pratica.
Cattivo stile
Sono d'accordo con @Osy sul fatto che OPEN/FETCH/CLOSE aggiunga codice completamente non necessario. Andrei ancora oltre e direi che non dovresti quasi mai usare CURSOR
.
Prima di tutto, normalmente vuoi fare il più possibile in semplice SQL. Se è necessario utilizzare PL/SQL, utilizzare un cursore implicito. Ti farà risparmiare una riga di codice e ti aiuterà a mantenere la logica correlata più vicina.
Credo fermamente nel mantenere le singole unità di codice il più piccole possibile. A prima vista, sembra un CURSOR
può aiutarti a farlo. Puoi definire il tuo SQL in alto in un posto, e quindi eseguire il ciclo PL/SQL in un secondo momento.
Ma in realtà, quel livello extra di indirizzamento non vale quasi mai la pena. A volte molta logica è in SQL e talvolta molta logica è in PL/SQL. Ma in pratica, raramente ha senso inserire molta logica complessa in entrambi. Il tuo codice di solito finisce per assomigliare a uno di questi:
for records in (<simple SQL>) loop
<complex PL/SQL>
end loop;
oppure:
for records in
(
<complex SQL>
) loop
<simple PL/SQL>;
end loop;
In ogni caso, una delle sezioni del tuo codice sarà molto piccola. La complessità della separazione di queste due sezioni di codice è maggiore della complessità di una singola sezione di codice più ampia. (Ma questa è ovviamente la mia opinione.)
Rendimento negativo
Ci sono implicazioni significative sulle prestazioni con l'utilizzo di OPEN/FETC/CLOSE. Questo metodo è molto più lento piuttosto che usare un cursore for loop o un cursore implicito.
Il compilatore può utilizzare automaticamente la raccolta di massa in alcuni cicli for. Ma, per citare la presentazione di Oracle "Prestazioni PL/SQL:sfatare i miti" , pagina 122:
Ecco un rapido esempio:
--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;
/