source

Oracle DUP_VAL_ON_INDEX 예외를 무시하면 얼마나 나쁜가요?

nicesource 2023. 9. 16. 09:28
반응형

Oracle DUP_VAL_ON_INDEX 예외를 무시하면 얼마나 나쁜가요?

사용자가 객체를 한 번 이상 본 적이 있는지 기록하는 테이블이 있습니다.

 HasViewed
     ObjectID  number (FK to Object table)
     UserId    number (FK to Users table)

두 필드 모두 NULL이 아니며 함께 Primary Key를 구성합니다.

제 질문은, 누군가가 (첫 번째 이후에) 오브젝트를 몇 번 봤는지는 신경 쓰지 않기 때문에, 삽입물을 다룰 수 있는 두 가지 옵션이 있다는 것입니다.

  • SELECT 카운트(*)를 수행하고 레코드가 없으면 새 레코드를 삽입합니다.
  • 항상 레코드를 삽입하고 DUP_VAL_ON_INDEX 예외(이미 이러한 레코드가 있음을 나타냄)를 던지는 경우에는 무시합니다.

두 번째 옵션을 선택하면 어떤 단점이 있습니까?

업데이트:

가장 좋은 방법은 "예외로 인한 오버헤드가 초기 선택으로 인한 오버헤드보다 더 나쁜가?"입니다.

DUP_VAL_ON_INDEX 예외는 가장 간단하게 코드화할 수 있기 때문에 보통 삽입하고 트랩합니다.이것은 삽입하기 전에 존재 여부를 확인하는 것보다 더 효율적입니다.저희가 취급하는 예외는 Oracle에서 제기하는 것이기 때문에 이를 "나쁜 냄새"(끔찍한 문구!)라고 생각하지 않습니다. 이는 흐름 제어 메커니즘으로 사용자 자신의 예외를 제기하는 것과는 다릅니다.

Igor의 코멘트 덕분에 나는 이것에 대해 두 가지 다른 벤치마크를 실행했습니다: (1) 첫 번째를 제외한 모든 삽입 시도가 중복되는 경우, (2) 모든 삽입이 중복되지 않는 경우.현실은 그 두 경우 사이 어딘가에 놓여 있을 것입니다.

참고: Oracle 10.2.0.3.0에서 수행된 테스트입니다.

사례 1: 대부분이 중복됩니다.

(중요한 요인에 의해) 가장 효율적인 접근법은 다음을 삽입하면서 존재 여부를 확인하는 것입니다.

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

결과(파싱 오버헤드를 방지하기 위해 한 번 실행한 후):

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

사례 2: 중복 없음

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

결과:

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

이 경우 DUP_VAL_ON_INDEX가 1마일 차이로 승리합니다.두 경우 모두 "삽입 전 선택"이 가장 느립니다.

따라서 삽입물이 중복되거나 중복되지 않을 상대적 가능성에 따라 옵션 1 또는 3을 선택해야 하는 것으로 보입니다.

저는 당신의 두 번째 옵션에 단점은 없다고 생각합니다.이름이 지정된 예외를 완벽하게 사용하는 것은 물론 조회 오버헤드도 피할 수 있다고 생각합니다.

이거 먹어봐요?

SELECT 1
FROM TABLE
WHERE OBJECTID = 'PRON_172.JPG' AND
      USERID='JCURRAN'

만약 거기에 1이 있다면 1을 반환해야 하고, 그렇지 않으면 NULL을 반환해야 합니다.

당신의 경우에는 무시해도 무방해 보이지만 성능을 위해서는 공통 경로에 대한 예외를 피해야 합니다."예외사항이 얼마나 일반적이겠는가?"라는 질문.무시해도 될 정도로 적습니까?아니면 그렇게 많은 다른 방법을 사용해야 합니까?

IMHO는 옵션 2와 함께 하는 것이 가장 좋습니다: 이미 언급된 것 이외에는 스레드 안전을 고려해야 합니다.옵션 1을 선택하고 여러 스레드가 PL/SQL 블록을 실행하는 경우 두 개 이상의 스레드가 동시에 실행되고 레코드가 없는 경우 모든 스레드가 삽입되도록 유도하고 고유한 제약 조건 오류가 발생할 수 있습니다.

일반적으로 예외 처리 속도가 느리지만, 거의 발생하지 않는 경우에는 쿼리의 오버헤드를 피할 수 있습니다.
주로 예외의 빈도에 따라 다르다고 생각하지만, 성능이 중요하다면 두 가지 접근 방식을 모두 사용한 벤치마킹을 제안하고 싶습니다.

일반적으로 일반적인 사건을 예외로 취급하는 것은 나쁜 냄새입니다. 이러한 이유로 다른 관점에서도 볼 수 있습니다.
예외적인 경우에는 예외로 취급해야 하며, 귀하의 접근 방식이 정확합니다.
일반적인 이벤트인 경우에는 해당 이벤트를 명시적으로 처리한 다음 레코드가 이미 삽입되어 있는지 확인해야 합니다.

언급URL : https://stackoverflow.com/questions/350860/how-bad-is-ignoring-oracle-dup-val-on-index-exception

반응형