Oracle
 sql >> Database >  >> RDS >> Oracle

È una cattiva pratica usare l'istruzione EXIT WHEN durante il ciclo di CURSOR in Oracle?

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;
/