Oracle ORA-12838 오류 원인과 해결 방법 완벽 가이드

ORA-12838
2026년 09월 18일 | DBMS Error 가이드

이 글에서 다루는 내용

ORA-12838 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.

ORA-12838 cannot read/modify an object after modifying it in parallel 는?

ORA-12838 에러는 병렬 DML(Parallel DML) 작업으로 객체를 수정한 후, 동일 트랜잭션 내에서 해당 객체를 다시 읽거나 수정하려 할 때 발생하는 Oracle 에러입니다. Oracle은 병렬 DML 수행 시 내부적으로 여러 병렬 슬레이브 프로세스를 사용하며, 이 과정에서 변경된 블록에 대한 일관성 보장이 복잡해지기 때문에 동일 트랜잭션 내의 추가 접근을 제한합니다. 즉, 병렬로 INSERT/UPDATE/DELETE를 수행한 뒤 커밋(COMMIT) 없이 같은 테이블에 접근하면 이 에러가 발생합니다.


주요 발생 원인

1. 병렬 DML 수행 후 커밋 없이 동일 테이블 재접근

가장 흔한 원인입니다. ALTER SESSION ENABLE PARALLEL DML 세션 설정이 활성화된 상태에서 병렬 INSERT/UPDATE/DELETE를 수행한 직후, 커밋 없이 동일 테이블을 SELECT하거나 추가 DML을 실행하면 Oracle이 읽기/수정 일관성을 보장할 수 없어 ORA-12838이 발생합니다. 특히 대용량 배치 작업이나 ETL 파이프라인에서 자주 나타납니다.

2. 병렬 INSERT 후 동일 트랜잭션에서 SELECT 수행

INSERT /+ PARALLEL / INTO ... SELECT ... 구문으로 병렬 삽입을 수행한 후, 같은 트랜잭션 내에서 해당 테이블에 대해 SELECT 쿼리를 실행하는 경우입니다. 병렬 DML이 완료되더라도 트랜잭션이 열려 있는 한, Oracle은 해당 객체에 대한 일관된 읽기 뷰를 제공하지 못합니다. 이로 인해 데이터 검증 쿼리나 후속 로직에서 에러가 발생합니다.

3. 동일 트랜잭션 내 여러 병렬 DML 연속 실행

하나의 트랜잭션 안에서 병렬 UPDATE 후 병렬 DELETE, 또는 병렬 INSERT 후 병렬 UPDATE처럼 연속으로 병렬 DML을 실행하는 경우에도 발생합니다. Oracle의 병렬 DML 설계상, 한 번의 병렬 조작이 끝난 후에는 반드시 커밋 또는 롤백으로 트랜잭션을 종료해야만 다음 DML 작업이 안전하게 수행될 수 있습니다.


해결 방법

원인 1 해결: 병렬 DML 후 즉시 COMMIT

병렬 DML 수행 후 반드시 COMMIT을 먼저 실행하고, 이후 SELECT 또는 추가 DML을 수행합니다.

-- 잘못된 예 (ORA-12838 발생)
ALTER SESSION ENABLE PARALLEL DML;

INSERT /*+ PARALLEL(t, 4) */ INTO target_table t
SELECT * FROM source_table;

-- 커밋 없이 동일 테이블 SELECT → ORA-12838 발생
SELECT COUNT(*) FROM target_table;

-- -----------------------------------------------
-- 올바른 예 (COMMIT 후 접근)
ALTER SESSION ENABLE PARALLEL DML;

INSERT /*+ PARALLEL(t, 4) */ INTO target_table t
SELECT * FROM source_table;

COMMIT;  -- 반드시 커밋 후 접근

SELECT COUNT(*) FROM target_table;  -- 정상 동작

원인 2 해결: 병렬 DML 비활성화 후 SELECT

병렬 DML 세션 설정을 비활성화하거나, 힌트를 제거하여 직렬(Serial) 모드로 수행 후 SELECT합니다.

-- 병렬 DML 비활성화
ALTER SESSION DISABLE PARALLEL DML;

INSERT INTO target_table
SELECT * FROM source_table;

-- 이후 SELECT 정상 동작
SELECT COUNT(*) FROM target_table;

-- 특정 구문에서만 병렬 비활성화 (힌트 제거)
INSERT INTO target_table
SELECT /*+ NO_PARALLEL */ * FROM source_table;

COMMIT;

원인 3 해결: 각 병렬 DML 사이에 COMMIT 삽입

연속적인 병렬 DML 작업 사이에 COMMIT을 삽입하여 각 작업이 독립적인 트랜잭션으로 처리되게 합니다.

-- 올바른 다중 병렬 DML 처리 패턴
ALTER SESSION ENABLE PARALLEL DML;

-- 1단계: 병렬 INSERT
INSERT /*+ PARALLEL(t, 4) */ INTO target_table t
SELECT * FROM source_table WHERE status = 'NEW';

COMMIT;  -- 첫 번째 커밋

-- 2단계: 병렬 UPDATE
UPDATE /*+ PARALLEL(t, 4) */ target_table t
SET    status = 'PROCESSED'
WHERE  status = 'NEW';

COMMIT;  -- 두 번째 커밋

-- 3단계: 병렬 DELETE
DELETE /*+ PARALLEL(t, 4) */ FROM target_table t
WHERE  status = 'OLD';

COMMIT;  -- 세 번째 커밋

임시 해결: 병렬 DML 전체 비활성화

근본적으로 병렬 DML이 불필요하다면 세션 수준에서 비활성화합니다.

-- 세션 수준 병렬 DML 비활성화
ALTER SESSION DISABLE PARALLEL DML;

-- 또는 시스템 수준에서 병렬 제한 확인
SELECT NAME, VALUE
FROM   V$PARAMETER
WHERE  NAME IN ('parallel_max_servers', 'parallel_dml_mode');

예방 방법

1. 병렬 DML 트랜잭션 설계 원칙 수립

병렬 DML을 사용하는 모든 배치 프로그램이나 ETL 스크립트에는 “병렬 DML → COMMIT → 다음 작업”의 원칙을 코딩 표준으로 정착시켜야 합니다. 특히 PL/SQL 프로시저 내에서 EXECUTE IMMEDIATE를 통해 병렬 DML을 실행하는 경우, 각 실행 후 명시적 COMMIT을 코드에 반드시 포함하도록 코드 리뷰 체크리스트를 구성하는 것이 효과적입니다.

-- PL/SQL에서 안전한 병렬 DML 패턴
BEGIN
    EXECUTE IMMEDIATE 'ALTER SESSION ENABLE PARALLEL DML';

    EXECUTE IMMEDIATE '
        INSERT /*+ PARALLEL(t, 4) */ INTO target_table t
        SELECT * FROM source_table
    ';

    COMMIT;  -- 명시적 커밋 필수

    EXECUTE IMMEDIATE 'ALTER SESSION DISABLE PARALLEL DML';
EXCEPTION
    WHEN OTHERS THEN
        ROLLBACK;
        RAISE;
END;
/

2. 모니터링 및 병렬 DML 세션 추적

운영 환경에서 병렬 DML 세션 상태를 주기적으로 모니터링하여, 비정상적으로 길게 열려 있는 병렬 트랜잭션을 조기에 감지합니다. 아래 쿼리를 활용하여 병렬 DML이 활성화된 세션과 트랜잭션을 추적할 수 있습니다.

-- 병렬 DML 활성 세션 확인
SELECT s.SID,
       s.SERIAL#,
       s.USERNAME,
       s.STATUS,
       s.SQL_ID,
       t.START_TIME,
       t.STATUS AS TX_STATUS
FROM   V$SESSION s
JOIN   V$TRANSACTION t ON s.TADDR = t.ADDR
WHERE  s.USERNAME IS NOT NULL
ORDER  BY t.START_TIME;

-- 병렬 슬레이브 실행 현황 확인
SELECT QC_SID,
       SERVER_SET#,
       DEGREE,
       REQ_DEGREE
FROM   V$PX_SESSION
WHERE  QCSID != SID;

관련 에러

  • ORA-12801: 병렬 쿼리 서버에서 에러 신호가 발생했을 때 나타나며, ORA-12838과 함께 출력되는 경우가 많습니다.
  • ORA-08177: 직렬화 불가(Serializable) 트랜잭션 격리 수준에서 충돌이 발생할 때 나타나며, 병렬 DML 환경에서 트랜잭션 격리 설정과 관련하여 함께 발생할 수 있습니다.
  • ORA-00060: 교착 상태(Deadlock) 에러로, 병렬 DML이 여러 세션과 얽혀 락(Lock) 충돌이 발생할 때 연관됩니다.
  • ORA-12839: ORA-12838의 유사 에러로, 병렬 모드에서 객체를 수정한 후 해당 객체를 수정하려 할 때 발생합니다. 두 에러는 거의 동일한 상황에서 발생하므로 함께 참고해야 합니다.
DBMS 에러 코드 시리즈

주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.

본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.

댓글 남기기