Oracle
 sql >> Database >  >> RDS >> Oracle

Quanto è grave ignorare l'eccezione Oracle DUP_VAL_ON_INDEX?

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.