Oracle
 sql >> Base de données >  >> RDS >> Oracle

Est-ce une mauvaise pratique d'utiliser l'instruction EXIT WHEN lors d'une boucle sur les CURSOR dans Oracle ?

Oui, beaucoup de gens suivent une mauvaise pratique.

Mauvais style

Je suis d'accord avec @Osy que OPEN/FETCH/CLOSE ajoute du code complètement inutile. J'irais encore plus loin et dirais que vous ne devriez presque jamais utiliser CURSOR .

Tout d'abord, vous voulez normalement faire autant que possible en SQL brut. Si vous devez utiliser PL/SQL, utilisez un curseur implicite. Cela vous fera économiser une ligne de code et vous aidera à garder la logique associée plus proche.

Je crois fermement qu'il faut garder les unités de code individuelles aussi petites que possible. À première vue, cela ressemble à un CURSOR peut vous aider à le faire. Vous pouvez définir votre SQL en haut à un seul endroit, puis faire la boucle PL/SQL plus tard.

Mais en réalité, cette couche supplémentaire d'indirection n'en vaut presque jamais la peine. Parfois, beaucoup de logique est en SQL, et parfois beaucoup de logique est en PL/SQL. Mais en pratique, il est rarement logique de mettre beaucoup de logique complexe dans les deux. Votre code finit généralement par ressembler à l'un de ces éléments :

for records in (<simple SQL>) loop
    <complex PL/SQL>
end loop;

ou :

for records in
(
    <complex SQL>
) loop
    <simple PL/SQL>;
end loop;

Dans tous les cas, l'une de vos sections de code sera très petite. La complexité de la séparation de ces deux sections de code est supérieure à la complexité d'une seule section de code plus grande. (Mais c'est évidemment mon opinion.)

Mauvaises performances

L'utilisation de OPEN/FETCH/CLOSE a des implications significatives sur les performances. Cette méthode est beaucoup plus lente que d'utiliser un curseur pour boucle ou un curseur implicite.

Le compilateur peut automatiquement utiliser la collecte en masse dans certaines boucles for. Mais, pour citer la présentation Oracle "Performances PL/SQL—Démystifier les mythes" , page 122 :

Voici un exemple rapide :

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