sql >> Base de Datos >  >> RDS >> Oracle

¿Qué tan malo es ignorar la excepción Oracle DUP_VAL_ON_INDEX?

Normalmente, solo insertaría y capturaría la excepción DUP_VAL_ON_INDEX, ya que es la forma más sencilla de codificar. Esto es más eficiente que verificar la existencia antes de insertar. No considero que hacer esto sea un "mal olor" (frase horrible) porque Oracle genera la excepción que manejamos; no es como generar sus propias excepciones como un mecanismo de control de flujo.

Gracias al comentario de Igor, ahora he ejecutado dos benchmarks diferentes en esto:(1) donde todos los intentos de inserción, excepto el primero, son duplicados, (2) donde todas las inserciones no son duplicadas. La realidad estará en algún lugar entre los dos casos.

Nota:pruebas realizadas en Oracle 10.2.0.3.0.

Caso 1:Mayormente duplicados

Parece que el enfoque más eficiente (por un factor significativo) es verificar la existencia MIENTRAS se inserta:

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;
/

Resultados (después de ejecutar una vez para evitar analizar los gastos generales):

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:sin duplicados

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;
/

Resultados:

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

En este caso, DUP_VAL_ON_INDEX gana por una milla. Tenga en cuenta que "seleccionar antes de insertar" es el más lento en ambos casos.

Por lo tanto, parece que debe elegir la opción 1 o 3 según la probabilidad relativa de que las inserciones sean o no duplicadas.