Normalmente inserirei e intercetterei l'eccezione DUP_VAL_ON_INDEX, poiché questa è la più semplice da codificare. Questo è più efficiente del controllo dell'esistenza prima dell'inserimento. Non considero questo un "cattivo odore" (frase orribile!) perché l'eccezione che gestiamo è sollevata da Oracle:non è come sollevare le tue eccezioni come meccanismo di controllo del flusso.
Grazie al commento di Igor ora ho eseguito due diversi benchmark su questo:(1) dove tutti i tentativi di inserimento tranne il primo sono duplicati, (2) dove tutti gli inserti non sono duplicati. La realtà si troverà da qualche parte tra i due casi.
Nota:test eseguiti su Oracle 10.2.0.3.0.
Caso 1:per lo più duplicati
Sembra che l'approccio più efficiente (di un fattore significativo) sia quello di verificarne l'esistenza MENTRE si inserisce:
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;
/
Risultati (dopo l'esecuzione una volta per evitare l'analisi dei costi generali):
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
Caso 2:nessun duplicato
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;
/
Risultati:
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 questo caso DUP_VAL_ON_INDEX vince di un miglio. Nota che "seleziona prima dell'inserimento" è il più lento in entrambi i casi.
Quindi sembra che dovresti scegliere l'opzione 1 o 3 in base alla probabilità relativa che gli inserti siano o meno duplicati.