MERGE 문은 WHEN 절의 기술 순서와 무관하게 UPDATE, INSERT 순서로 동작한다. 이때 ON 절은 UPDATE 문의 WHERE 절과 유사하게 동작한다. 이로 인해 예상치 못한 에러가 발생할 수 있다.
테스트를 위해 아래의 테이블을 생성하자.
-- 1 DROP TABLE t1 PURGE; CREATE TABLE t1 (c1 VARCHAR2(1), c2 NUMBER); ALTER TABLE t1 ADD CONSTRAINT t1_pk PRIMARY KEY (c1);
-- 2: S1 MERGE INTO t1 USING DUAL ON (c1 = 'A') WHEN MATCHED THEN UPDATE SET c2 = c2 + 1 WHEN NOT MATCHED THEN INSERT VALUES ('A', 1); 1 행이 병합되었습니다.
-- 3: S2 MERGE INTO t1 USING DUAL ON (c1 = 'A') WHEN MATCHED THEN UPDATE SET c2 = c2 + 1 WHEN NOT MATCHED THEN INSERT VALUES ('A', 1); -- 블로킹
-- 4: S1 COMMIT; 커밋이 완료되었습니다.
-- 5: S2 ORA-00001: 무결성 제약 조건(SCOTT.T1_PK)에 위배됩니다
예제의 MERGE 문은 아래 코드와 유사하게 동작한다. UPDATE 문의 WHERE 절은 consistent read로 동작한다. S2 세션의 MERGE 문은 UPDATE 대상이 없어 INSERT 문이 수행했지만, S1 세션이 동일 PK로 INSERT 문이 수행하고 있어 블로킹이 발생한 것이다.
-- 6 BEGIN UPDATE t1 SET c2 = c2 + 1 WHERE c1 = 'A'; IF SQL%ROWCOUNT = 0 THEN INSERT INTO t1 VALUES ('A', 1); END IF; END;
-- 7: S1 BEGIN INSERT INTO t1 VALUES ('B', 1); EXCEPTION WHEN DUP_VAL_ON_INDEX THEN UPDATE t1 SET c2 = c2 + 1 WHERE c1 = 'B'; END; / PL/SQL 처리가 정상적으로 완료되었습니다.
-- 8: S2 BEGIN INSERT INTO t1 VALUES ('B', 1); EXCEPTION WHEN DUP_VAL_ON_INDEX THEN UPDATE t1 SET c2 = c2 + 1 WHERE c1 = 'B'; END; / -- 블로킹
-- 9: S1 COMMIT; 커밋이 완료되었습니다.
S2 세션은 에러가 발생하지 않고 UPDATE 문이 수행된다. 에러는 발생하지 않지만 UPDATE 문으로 인해 동시성 저하는 여전히 발생할 수 있다는 점에 주의해야 한다.
-- 10: S2 PL/SQL 처리가 정상적으로 완료되었습니다. SELECT * FROM t1; C1 C2 -- -- A 1 B 2 2 행이 선택되었습니다.
'Oracle > SQL' 카테고리의 다른 글
특정 행의 계층 경로 조회 (0) | 2020.03.03 |
---|---|
연속 값 그룹핑 (0) | 2019.09.02 |
ORA-00937 에러 (0) | 2019.04.22 |
NVL, NVL2 함수의 인수 평가 (0) | 2019.03.29 |
용어 단어 분리 (0) | 2019.03.14 |