Post

(Oracle) ignore_row_on_dupkey_index 동작이 11g와 19c에서 다른 문제 (bug)

상황

  • tbl 테이블 PK는 tbl_no이고, tbl_tmp에는 unique constraint 같은 것이 안걸려 있는 상황.
  • 요구사항 1) tbl 테이블에 이미 존재하는 tbl_no row를 insert하는 경우, 에러 없이 수행되어야 함
  • 요구사항 2) tbl_tmp 테이블에 tbl_no가 동일한 row가 2개 이상 존재하는 경우, 에러 없이 1개만 insert 되어야 함

11g, 19c 버전에 따라 동작이 다른 ignore_row_on_dupkey_index 힌트

  • 실행 예제
  • 요구사항 1) tbl 테이블에 이미 존재하는 tbl_no row를 insert하는 경우, 에러 없이 수행되어야 함
    • 11g : O
    • 19c : O
  • 요구사항 2) tbl_tmp 테이블에 tbl_no가 동일한 row가 2개 이상 존재하는 경우, 에러 없이 1개만 insert 되어야 함
    • 11g : O
    • 19c : X(PK violation)

해결책 : MERGE INTO를 사용하면 어떨까?

1
2
3
4
5
6
7
8
MERGE INTO tbl e
USING tbl_tmp t
ON (e.tbl_NO = t.tbl_NO)
WHEN NOT MATCHED THEN
    INSERT (e.tbl_no) 
    VALUES (t.tbl_no);
---
[2022-02-07 11:54:10] [23000][1] ORA-00001: 무결성 제약 조건(tbl_PK) 위배됩니다
  • 요구사항 1) tbl 테이블에 이미 존재하는 tbl_no row를 insert하는 경우, 에러 없이 수행되어야 함
    • 11g : O
    • 19c : O
  • 요구사항 2) tbl_tmp 테이블에 tbl_no가 동일한 row가 2개 이상 존재하는 경우, 에러 없이 1개만 insert 되어야 함
    • 11g : X
    • 19c : X(PK violation)
    • MERGE INTO에 UPDATE 문 추가해도X

요구사항 1, 2를 모두 만족하는 해결책은?

  • 근본적으로 tbl_tmp 테이블에 중복 로그가 생기지 않도록 비즈니스 로직을 고친다
  • tbl_tmp 가져올 때, 서브쿼리로 DISTINCT 해서 가져온다.
tbl_tmp 중복제거
1
2
3
SELECT *
FROM tbl_tmp
WHERE ROWID IN (SELECT MAX(ROWID) FROM tbl_tmp GROUP BY tbl_no);
tbl_tmp 중복제거 - MERGE INTO 사용하는 방법
1
2
3
MERGE INTO tbl e
USING (SELECT * FROM tbl_tmp WHERE ROWID IN (SELECT MAX(ROWID) FROM tbl_TMP GROUP BY tbl_NO)) t
...
tbl_tmp 중복제거 - hint 사용하는 방법
1
2
3
4
5
6
7
8
9
INSERT /*+ ignore_row_on_dupkey_index(tbl(tbl_no)) */
INTO tbl
(
   ...
)
SELECT
    ...
FROM tbl_tmp
WHERE ROWID IN (SELECT MAX(ROWID) FROM tbl_tmp GROUP BY tbl_no);
This post is licensed under CC BY 4.0 by the author.