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 error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.