Ik zou normaal gesproken gewoon de DUP_VAL_ON_INDEX-uitzondering invoegen en vangen, omdat dit het eenvoudigst te coderen is. Dit is efficiënter dan het controleren op bestaan voordat het wordt ingevoegd. Ik beschouw dit niet als een "slechte stank" (vreselijke uitdrukking!) omdat de uitzondering die we behandelen door Oracle is - het is niet alsof je je eigen uitzonderingen opheft als een stroomcontrolemechanisme.
Dankzij de opmerking van Igor heb ik hier nu twee verschillende benchmarks op uitgevoerd:(1) waarbij alle invoegpogingen behalve de eerste duplicaten zijn, (2) waarbij alle invoegingen geen duplicaten zijn. De werkelijkheid zal ergens tussen de twee gevallen in liggen.
Opmerking:tests uitgevoerd op Oracle 10.2.0.3.0.
Geval 1:Meestal duplicaten
Het lijkt erop dat de meest efficiënte benadering (met een significante factor) is om te controleren op bestaan TIJDENS het invoegen:
prompt 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;
/
Resultaten (na één keer uitvoeren om overheadkosten te voorkomen):
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
Geval 2:geen duplicaten
prompt 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;
/
Resultaten:
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
In dit geval wint DUP_VAL_ON_INDEX met een mijl. Merk op dat "selecteren voor invoegen" in beide gevallen het langzaamst is.
Het lijkt er dus op dat u optie 1 of 3 moet kiezen op basis van de relatieve kans dat inserts al dan niet duplicaten zijn.