Zwykle po prostu wstawiam i łapie wyjątek DUP_VAL_ON_INDEX, ponieważ jest to najprostszy kod. Jest to bardziej wydajne niż sprawdzanie istnienia przed wstawieniem. Nie uważam tego za "nieprzyjemny zapach" (okropna fraza!), ponieważ wyjątek, który obsługujemy, jest zgłaszany przez Oracle - to nie jest jak podnoszenie własnych wyjątków jako mechanizmu kontroli przepływu.
Dzięki komentarzowi Igora uruchomiłem teraz dwa różne testy porównawcze:(1) gdzie wszystkie próby wstawienia oprócz pierwszej są duplikatami, (2) gdzie wszystkie wstawki nie są duplikatami. Rzeczywistość będzie leżała gdzieś pomiędzy tymi dwoma przypadkami.
Uwaga:testy przeprowadzone na Oracle 10.2.0.3.0.
Przypadek 1:głównie duplikaty
Wydaje się, że najskuteczniejszym podejściem (z uwagi na istotny czynnik) jest sprawdzenie istnienia PODCZAS wstawiania:
Monitprompt 1) Check DUP_VAL_ON_INDEX
begin
for i in 1..1000 loop
begin
insert into hasviewed values(7782,20);
exception
when dup_val_on_index then
null;
end;
end loop
rollback;
end;
/
prompt 2) Test if row exists before inserting
declare
dummy integer;
begin
for i in 1..1000 loop
select count(*) into dummy
from hasviewed
where objectid=7782 and userid=20;
if dummy = 0 then
insert into hasviewed values(7782,20);
end if;
end loop;
rollback;
end;
/
prompt 3) Test if row exists while inserting
begin
for i in 1..1000 loop
insert into hasviewed
select 7782,20 from dual
where not exists (select null
from hasviewed
where objectid=7782 and userid=20);
end loop;
rollback;
end;
/
Wyniki (po jednokrotnym uruchomieniu, aby uniknąć analizowania kosztów ogólnych):
1) Check DUP_VAL_ON_INDEX
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.54
2) Test if row exists before inserting
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.59
3) Test if row exists while inserting
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.20
Przypadek 2:brak duplikatów
Monitprompt 1) Check DUP_VAL_ON_INDEX
begin
for i in 1..1000 loop
begin
insert into hasviewed values(7782,i);
exception
when dup_val_on_index then
null;
end;
end loop
rollback;
end;
/
prompt 2) Test if row exists before inserting
declare
dummy integer;
begin
for i in 1..1000 loop
select count(*) into dummy
from hasviewed
where objectid=7782 and userid=i;
if dummy = 0 then
insert into hasviewed values(7782,i);
end if;
end loop;
rollback;
end;
/
prompt 3) Test if row exists while inserting
begin
for i in 1..1000 loop
insert into hasviewed
select 7782,i from dual
where not exists (select null
from hasviewed
where objectid=7782 and userid=i);
end loop;
rollback;
end;
/
Wyniki:
1) Check DUP_VAL_ON_INDEX
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.15
2) Test if row exists before inserting
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.76
3) Test if row exists while inserting
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.71
W tym przypadku DUP_VAL_ON_INDEX wygrywa o milę. Zauważ, że "wybierz przed wstawieniem" jest najwolniejszy w obu przypadkach.
Wygląda więc na to, że powinieneś wybrać opcję 1 lub 3 w zależności od względnego prawdopodobieństwa, że wstawki są lub nie są duplikatami.