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

ORA-01591
2026년 07월 25일 | DBMS Error 가이드

이 글에서 다루는 내용

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

ORA-01591 lock held by in-doubt distributed transaction identifier 는?

ORA-01591 에러는 분산 트랜잭션(Distributed Transaction)이 완료되지 못하고 “in-doubt” 상태로 남아 있을 때, 해당 트랜잭션이 보유한 락(Lock)으로 인해 다른 세션이 동일 리소스에 접근하지 못할 때 발생합니다. 이 에러는 주로 두 개 이상의 Oracle 데이터베이스 간에 데이터베이스 링크(DB Link)를 통한 분산 트랜잭션이 네트워크 장애, 원격 DB 다운, 또는 커밋/롤백 중 통신 오류로 인해 정상적으로 종료되지 않은 경우 발생합니다. Oracle의 2PC(Two-Phase Commit) 프로토콜 처리 중 코디네이터 또는 참여자 노드가 응답하지 못하는 상황에서 트랜잭션이 미결 상태로 오랫동안 유지되면, 해당 세그먼트에 대한 접근이 완전히 차단될 수 있습니다.


주요 발생 원인

  • 네트워크 장애 또는 원격 DB 연결 중단으로 인한 2PC 실패

Oracle의 Two-Phase Commit(2PC) 프로토콜은 분산 트랜잭션의 원자성을 보장하기 위해 Prepare 단계와 Commit 단계를 거칩니다. 그러나 Prepare 단계 이후, Commit 단계 진입 직전에 네트워크 장애가 발생하거나 원격 데이터베이스가 갑자기 다운되면 트랜잭션은 “in-doubt” 상태로 전환됩니다. 이 상태에서는 로컬 DB가 해당 트랜잭션을 커밋해야 할지 롤백해야 할지 결정하지 못하기 때문에 관련 리소스에 락이 계속 유지됩니다. 결과적으로 해당 행(Row) 또는 세그먼트에 접근하려는 다른 트랜잭션은 ORA-01591을 만나게 됩니다.

  • RECO(Recoverer) 프로세스의 장기 미결 또는 비정상 동작

Oracle은 in-doubt 분산 트랜잭션을 자동으로 해결하기 위해 백그라운드 프로세스인 RECO(Recoverer Process)를 운영합니다. 그러나 원격 DB가 장시간 다운 상태를 유지하거나, 네트워크 복구가 이루어지지 않으면 RECO는 주기적으로 재시도는 하지만 영구적으로 해결하지 못합니다. 이 경우 DBA_2PC_PENDING 뷰에서 확인할 수 있는 미결 트랜잭션이 누적되어 점점 더 많은 리소스 락이 발생하고, 운영 중인 애플리케이션 전반에 성능 문제와 에러가 확산됩니다. RECO가 정상적으로 동작하지 않을 경우 DBA가 수동으로 개입해야 합니다.

  • DB Link를 통한 DDL 또는 대량 DML 수행 중 세션 단절

애플리케이션에서 DB Link를 통해 원격 테이블에 대규모 INSERT, UPDATE, DELETE 또는 DDL을 수행하는 도중 세션이 강제 종료되거나 클라이언트가 비정상 종료되는 경우에도 이 에러가 발생합니다. 특히 자동 커밋이 설정되지 않은 환경에서 대량 작업 도중 세션이 끊기면 로컬 DB와 원격 DB의 트랜잭션 상태 불일치가 발생합니다. 이 상황은 야간 배치 작업, ETL 프로세스, 대규모 데이터 마이그레이션 작업 시 빈번히 발생하므로 각별한 주의가 필요합니다.


해결 방법

Step 1: 현재 in-doubt 트랜잭션 확인

먼저 DBA_2PC_PENDING 뷰를 통해 미결 분산 트랜잭션 목록을 확인합니다.

-- in-doubt 분산 트랜잭션 전체 조회
SELECT local_tran_id,
       global_tran_id,
       state,
       mixed,
       advice,
       tran_comment,
       fail_time,
       force_time,
       retry_time,
       os_user,
       os_terminal,
       host,
       db_user,
       parent_local_tran_id
FROM   dba_2pc_pending
ORDER  BY fail_time;

Step 2: 락을 보유한 트랜잭션과 대기 세션 확인

-- in-doubt 트랜잭션과 연관된 락 정보 조회
SELECT s.sid,
       s.serial#,
       s.username,
       s.status,
       s.wait_class,
       s.event,
       l.type,
       l.id1,
       l.id2,
       l.lmode,
       l.request
FROM   v$session s
JOIN   v$lock    l ON s.sid = l.sid
WHERE  l.type = 'TX'
AND    l.lmode = 0
AND    l.request > 0;

-- DBA_2PC_PENDING과 락 연관 관계 추가 확인
SELECT p.local_tran_id,
       p.state,
       p.global_tran_id,
       l.sid,
       l.type,
       l.lmode
FROM   dba_2pc_pending p,
       v$lock          l
WHERE  l.type = 'XA';

Step 3: 수동으로 트랜잭션 강제 커밋 또는 롤백

RECO가 자동으로 해결하지 못하는 경우, DBA가 수동으로 처리해야 합니다. 반드시 원격 DB 관리자와 협의하여 데이터 정합성을 확인한 후 수행하십시오.

-- 방법 1: 강제 커밋 (원격 DB에서 해당 트랜잭션이 커밋되었음을 확인한 경우)
COMMIT FORCE 'local_tran_id';

-- 예시
COMMIT FORCE '1.17.123456';

-- 방법 2: 강제 롤백 (원격 DB에서 롤백되었음을 확인한 경우)
ROLLBACK FORCE 'local_tran_id';

-- 예시
ROLLBACK FORCE '1.17.123456';

Step 4: 강제 처리 후 DBA_2PC_PENDING 정리

강제 커밋/롤백 이후에도 DBA_2PC_PENDING에 레코드가 남아있는 경우 수동으로 삭제합니다.

-- FORCE COMMIT/ROLLBACK 이후에도 남은 레코드 정리
-- (반드시 SYSDBA 또는 DBA 권한 필요)
EXECUTE DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('local_tran_id');

-- 예시
EXECUTE DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('1.17.123456');

-- 정리 후 확인
SELECT COUNT(*) FROM dba_2pc_pending;

Step 5: RECO 프로세스 상태 점검

-- RECO 백그라운드 프로세스 실행 여부 확인
SELECT name, description, status
FROM   v$bgprocess
WHERE  name = 'RECO';

-- 분산 트랜잭션 관련 파라미터 확인
SELECT name, value
FROM   v$parameter
WHERE  name IN ('distributed_transactions',
                'commit_point_strength',
                'db_name');

예방 방법

  • 분산 트랜잭션 모니터링 자동화 및 알림 설정

운영 환경에서는 DBA_2PC_PENDING을 주기적으로 모니터링하는 자동화 스크립트 또는 OEM(Oracle Enterprise Manager) 알림을 구성하여 in-doubt 트랜잭션이 일정 시간(예: 30분) 이상 지속될 경우 즉각 DBA에게 알림이 가도록 구성해야 합니다. 또한 COMMIT_POINT_STRENGTH 파라미터를 상호 연결된 DB 간 적절하게 설정하여 커밋 결정 주체를 명확히 하는 것이 중요합니다.

“`sql

— 예방용 모니터링 쿼리 (스케줄러 잡으로 등록 권장)

SELECT COUNT(*) AS pending_count,

MIN(fail_time) AS oldest_fail_time

FROM dba_2pc_pending

WHERE fail_time < SYSDATE - (30/1440); -- 30분 이상 미결 상태

“`

  • DB Link 사용 트랜잭션의 명시적 커밋 및 예외 처리 강화

애플리케이션 레벨에서 DB Link를 사용하는 모든 트랜잭션에는 명시적인 COMMIT 또는 ROLLBACK을 포함하고, 예외 발생 시 반드시 예외 핸들러에서 ROLLBACK을 수행하도록 코딩 표준을 수립해야 합니다. 특히 PL/SQL 내에서 DB Link를 통해 원격 프로시저를 호출하거나 DML을 수행할 때는 EXCEPTION 블록에서 명확히 처리해야 합니다.

“`sql

— 권장 패턴: DB Link 사용 트랜잭션 예외 처리

BEGIN

INSERT INTO remote_table@remote_db_link (col1, col2)

VALUES (‘value1’, ‘value2’);

UPDATE local_table SET status = ‘PROCESSED’

WHERE id = 1;

COMMIT; — 명시적 커밋 필수

EXCEPTION

WHEN OTHERS THEN

ROLLBACK; — 예외 시 명시적 롤백

RAISE;

END;

/

“`


관련 에러

  • ORA-01578: 데이터 블록 손상(Data Block Corruption)과 함께 분산 트랜잭션 복구 실패 시 동반 발생할 수 있습니다.
  • ORA-02050: 분산 트랜잭션이 롤백되었고 일부 원격 DB는 in-doubt 상태임을 나타내는 에러로, ORA-01591과 밀접하게 연관됩니다.
  • ORA-02054: 트랜잭션이 in-doubt 상태임을 직접적으로 알리는 에러이며, ORA-01591 발생 전 선행 에러로 자주 등장합니다.
  • ORA-02058: COMMIT FORCE 또는 ROLLBACK FORCE 실행 시 해당 트랜잭션 ID를 찾을 수 없을 때 발생하며, 이미 RECO가 자동 처리했을 가능성을 시사합니다.
  • ORA-01013: 사용자 요청에 의한 작업 취소로, 장시간 대기 후 세션이 타임아웃되어 분산 트랜잭션 문제와 함께 발생하기도 합니다.

DBMS 에러 코드 시리즈

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

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

댓글 남기기