Znacznie poprawia wydajność (średnia w dziesiątkach procent) w przypadku zapytań, których nie można rozwiązać za pomocą prostego wyszukiwania pojedynczego indeksu, np. łączenia tabel. Jednak może potencjalnie ukryć błąd danych/aplikacji.
Zróbmy stolik:
create table t (id number(10,0), padding varchar2(1000));
--celowo nie używaj PK, aby przykład był tak prosty, jak to tylko możliwe. Wypełnienie służy do symulacji rzeczywistego ładowania danych w każdym rekordzie
z wieloma rekordami:
insert into t (id, padding)
select rownum, rpad(' ', 1000) from dual connect by level < 10000
Teraz, jeśli zapytasz o coś takiego
select 1 into ll_exists
from t where id = 5;
DB musi przejść przez całą tabelę, niezależnie od tego, czy znalazła jedyny pasujący rekord w pierwszym bloku danych (którego, nawiasem mówiąc, nie wiemy, ponieważ można go wstawić na wiele różnych sposobów), czy w ostatnim. To dlatego, że nie wie, że jest tylko jeden pasujący rekord. Z drugiej strony, jeśli użyjesz ... i rownum =1, może przestać przeglądać dane po znalezieniu rekordu, ponieważ powiedziałeś mu, że nie ma (lub nie jest potrzebny) innego pasującego rekordu.
Wadą jest to, że przy ograniczeniu numeru wiersza możesz uzyskać niedeterministyczne wyniki, jeśli dane zawierają więcej niż jeden możliwy rekord.Jeśli zapytanie było
select id into ll_id
from t where mod (id, 2) = 1
and rownum = 1;
wtedy mogę otrzymać od DB odpowiedź 1 i 3 oraz 123 ... zamówienie nie jest gwarantowane i to jest konsekwencja. (bez klauzuli rownum otrzymałbym wyjątek TOO_MANY_ROWS. To zależy od sytuacji, która jest gorsza)
Jeśli naprawdę chcesz zapytać, które testuje istnienie, NAPISZ TO W TEN SPOSÓB.
begin
select 'It does'
into ls_exists
from dual where
exists (your_original_query_without_rownum);
do_something_when_it_does_exist
exception
when no_data_found then
do_something_when_it_doesn't_exist
end;