Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

É uma prática ruim usar a instrução EXIT WHEN ao fazer um loop por CURSORs no Oracle?


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