Tak, wiele osób stosuje złą praktykę.
Zły styl
Zgadzam się z @Osy, że OPEN/FETCH/CLOSE dodaje zupełnie niepotrzebny kod. Pójdę jeszcze dalej i powiem, że prawie nigdy nie należy używać CURSOR
.
Po pierwsze, zwykle chcesz zrobić jak najwięcej w zwykłym SQL. Jeśli musisz użyć PL/SQL, użyj niejawnego kursora. Zaoszczędzi ci to linijki kodu i pomoże ci utrzymać powiązaną logikę bliżej siebie.
Mocno wierzę w to, aby poszczególne jednostki kodu były jak najmniejsze. Na pierwszy rzut oka wygląda na CURSOR
może ci w tym pomóc. Możesz zdefiniować swój SQL od góry w jednym miejscu, a następnie wykonać pętlę PL/SQL później.
Ale w rzeczywistości ta dodatkowa warstwa pośredniości prawie nigdy nie jest tego warta. Czasami dużo logiki jest w SQL, a czasami dużo logiki jest w PL/SQL. Ale w praktyce rzadko ma sens umieszczanie w obu bardzo złożonej logice. Twój kod zwykle wygląda jak jeden z tych:
for records in (<simple SQL>) loop
<complex PL/SQL>
end loop;
lub:
for records in
(
<complex SQL>
) loop
<simple PL/SQL>;
end loop;
Tak czy inaczej, jedna z sekcji twojego kodu będzie bardzo mała. Złożoność rozdzielenia tych dwóch sekcji kodu jest większa niż złożoność większej, pojedynczej sekcji kodu. (Ale to oczywiście moja opinia.)
Zła wydajność
Korzystanie z funkcji OPEN/FETCH/CLOSE ma poważne konsekwencje dla wydajności. Ta metoda jest znacznie wolniejsza niż używanie kursora pętli lub niejawnego kursora.
Kompilator może automatycznie używać zbierania zbiorczego w niektórych pętlach for. Ale, cytując prezentację Oracle, "Wydajność PL/SQL — obalanie mitów" , strona 122:
Oto krótki przykład:
--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;
/