Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Quão ruim é ignorar a exceção DUP_VAL_ON_INDEX do Oracle?


Normalmente, eu apenas inseriria e interceptaria a exceção DUP_VAL_ON_INDEX, pois essa é a mais simples de codificar. Isso é mais eficiente do que verificar a existência antes de inserir. Eu não considero isso um "cheiro ruim" (frase horrível!) porque a exceção que tratamos é levantada pelo Oracle - não é como levantar suas próprias exceções como um mecanismo de controle de fluxo.

Graças ao comentário de Igor, agora executei dois benchmarks diferentes sobre isso:(1) onde todas as tentativas de inserção, exceto a primeira, são duplicadas, (2) onde todas as inserções não são duplicadas. A realidade estará em algum lugar entre os dois casos.

Nota:testes realizados no Oracle 10.2.0.3.0.

Caso 1:principalmente duplicatas

Parece que a abordagem mais eficiente (por um fator significativo) é verificar a existência AO inserir:
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 (depois de executar uma vez para evitar sobrecargas de análise):
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:sem duplicatas
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

Neste caso, DUP_VAL_ON_INDEX ganha por uma milha. Observe que "selecionar antes de inserir" é o mais lento em ambos os casos.

Portanto, parece que você deve escolher a opção 1 ou 3 de acordo com a probabilidade relativa de as inserções serem ou não duplicadas.