2026년 10월 23일 | DBMS Error 가이드
이 글에서 다루는 내용
ORA-00051 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
ORA-00051 timeout occurred while waiting for a resource 는?
ORA-00051 에러는 Oracle 데이터베이스에서 특정 리소스(주로 락(Lock) 또는 래치(Latch))를 획득하기 위해 대기하던 중 설정된 타임아웃 시간이 초과되었을 때 발생하는 에러입니다. 주로 분산 트랜잭션(Distributed Transaction) 환경에서 원격 데이터베이스와의 통신이 지연되거나, 로컬 환경에서 특정 리소스에 대한 경합이 심할 때 나타납니다. 이 에러는 단순한 쿼리 성능 문제를 넘어 시스템 전반의 가용성에 영향을 미칠 수 있으므로 신속하고 정확한 진단이 필요합니다.
주요 발생 원인
1. 분산 트랜잭션(Distributed Transaction)에서의 네트워크 지연 또는 원격 DB 응답 없음
분산 트랜잭션 환경에서 Database Link를 통해 원격 Oracle 인스턴스와 통신할 때, 네트워크 불안정이나 원격 DB의 응답 지연으로 인해 타임아웃이 발생하는 가장 흔한 원인입니다. DISTRIBUTED_LOCK_TIMEOUT 파라미터(기본값 60초)에 의해 제어되며, 이 시간 내에 원격 리소스를 확보하지 못하면 ORA-00051이 발생합니다. 특히 원격 DB가 장시간 락을 보유하고 있거나, 네트워크 패킷 손실이 발생하는 경우에 자주 목격됩니다.
2. 과도한 락(Lock) 경합으로 인한 대기 시간 초과
동일한 테이블 또는 행(Row)에 대해 다수의 세션이 동시에 DML 작업을 수행할 때 락 경합이 발생하며, 특정 세션이 락을 오랫동안 해제하지 않으면 대기 중인 세션에서 타임아웃이 발생할 수 있습니다. 특히 SELECT ... FOR UPDATE WAIT n 구문이나 LOCK TABLE ... NOWAIT 등의 명시적 락 관련 구문에서 이 에러가 발생하기도 합니다. 배치 작업이나 대용량 데이터 처리 중 트랜잭션이 오랫동안 커밋되지 않고 유지될 때 특히 위험합니다.
3. 래치(Latch) 또는 내부 리소스 경합
Oracle 내부적으로 공유 메모리 구조를 보호하기 위해 사용하는 래치(Latch)에 대한 경합이 극심해질 경우에도 이 에러가 간접적으로 유발될 수 있습니다. 특히 shared pool latch, library cache latch 등에 대한 경합이 심한 환경에서 내부 타임아웃이 연쇄적으로 발생할 수 있습니다. SGA 크기 부족, 하드 파싱(Hard Parsing) 과다, 또는 CPU 자원 포화 상태에서 빈번히 관찰됩니다.
해결 방법
원인 1: 분산 트랜잭션 타임아웃 해결
현재 DISTRIBUTED_LOCK_TIMEOUT 파라미터 값을 확인하고 적절히 조정합니다.
-- 현재 DISTRIBUTED_LOCK_TIMEOUT 파라미터 확인
SHOW PARAMETER DISTRIBUTED_LOCK_TIMEOUT;
-- 파라미터 조정 (단위: 초, 기본값 60)
ALTER SYSTEM SET DISTRIBUTED_LOCK_TIMEOUT = 120 SCOPE=BOTH;
-- 인-더우트(In-Doubt) 분산 트랜잭션 확인
SELECT LOCAL_TRAN_ID, GLOBAL_TRAN_ID, STATE, MIXED, HOST, DB_USER
FROM DBA_2PC_PENDING;
-- In-Doubt 트랜잭션 강제 커밋 또는 롤백
-- (DBA 판단 하에 수행, 데이터 무결성 확인 필수)
COMMIT FORCE 'local_tran_id';
-- 또는
ROLLBACK FORCE 'local_tran_id';
-- 연결 중인 DB Link 확인
SELECT DB_LINK, USERNAME, HOST, CREATED
FROM DBA_DB_LINKS;
원인 2: 락 경합 진단 및 해결
현재 락을 보유 중인 세션과 대기 중인 세션을 식별하고 해소합니다.
-- 현재 락 보유 세션 및 대기 세션 조회
SELECT
l.sid AS blocking_sid,
s.serial# AS blocking_serial,
s.username AS blocking_user,
s.status AS blocking_status,
l.type AS lock_type,
l.id1,
l.id2,
l.lmode,
l.request,
l.ctime AS wait_time_sec
FROM v$lock l
JOIN v$session s ON l.sid = s.sid
WHERE l.block = 1
ORDER BY l.ctime DESC;
-- Blocking 세션과 Blocked 세션 연계 조회
SELECT
w.sid AS waiting_sid,
w.serial# AS waiting_serial,
w.username AS waiting_user,
b.sid AS blocking_sid,
b.username AS blocking_user,
w.sql_id AS waiting_sql_id,
w.event AS wait_event,
w.seconds_in_wait
FROM v$session w
JOIN v$session b ON w.blocking_session = b.sid
WHERE w.blocking_session IS NOT NULL;
-- 특정 오브젝트에 대한 락 조회
SELECT
o.object_name,
o.object_type,
s.sid,
s.serial#,
s.username,
l.lmode,
l.request
FROM v$lock l
JOIN v$session s ON l.sid = s.sid
JOIN dba_objects o ON l.id1 = o.object_id
WHERE l.type = 'TM';
-- 락을 보유한 세션 강제 종료 (최후 수단)
ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE;
-- 예) 세션 155, serial# 2345 종료
ALTER SYSTEM KILL SESSION '155,2345' IMMEDIATE;
원인 3: 래치 경합 진단
-- 래치 경합 현황 확인
SELECT
name,
gets,
misses,
sleeps,
immediate_gets,
immediate_misses,
ROUND(misses / DECODE(gets, 0, 1, gets) * 100, 2) AS miss_ratio_pct
FROM v$latch
WHERE misses > 0
ORDER BY misses DESC
FETCH FIRST 10 ROWS ONLY;
-- Library Cache 관련 상세 래치 현황
SELECT
name,
gets,
misses,
sleeps,
spin_gets
FROM v$latch_children
WHERE name LIKE '%library cache%'
ORDER BY sleeps DESC;
-- 하드 파싱 현황 확인 (래치 경합의 주요 원인)
SELECT
s.sql_id,
s.sql_text,
s.parse_calls,
s.executions,
s.invalidations,
ROUND(s.parse_calls / DECODE(s.executions, 0, 1, s.executions) * 100, 2) AS parse_ratio
FROM v$sql s
WHERE s.parse_calls > 100
ORDER BY s.parse_calls DESC
FETCH FIRST 20 ROWS ONLY;
-- SGA 크기 확인
SELECT name, bytes / 1024 / 1024 AS mb
FROM v$sgastat
WHERE name IN ('free memory', 'sql area', 'library cache')
ORDER BY 2 DESC;
-- Shared Pool 사이즈 증설 (필요 시)
ALTER SYSTEM SET SHARED_POOL_SIZE = 512M SCOPE=BOTH;
예방 방법
1. 분산 트랜잭션 관리 강화 및 모니터링 자동화
분산 트랜잭션을 사용하는 환경에서는 주기적으로 DBA_2PC_PENDING 뷰를 모니터링하여 In-Doubt 트랜잭션을 조기에 발견하고 처리하는 자동화 스크립트를 운영하는 것이 중요합니다. 또한 네트워크 인프라를 정기적으로 점검하고, Database Link를 통한 연결에 대해 적절한 커넥션 타임아웃 및 재시도 로직을 애플리케이션 레벨에서 구현하는 것이 권장됩니다.
-- In-Doubt 트랜잭션 자동 모니터링 (스케줄러 활용 예시)
BEGIN
DBMS_SCHEDULER.CREATE_JOB(
job_name => 'MONITOR_2PC_PENDING',
job_type => 'PLSQL_BLOCK',
job_action => '
DECLARE
v_count NUMBER;
BEGIN
SELECT COUNT(*) INTO v_count FROM DBA_2PC_PENDING
WHERE SYSDATE - TO_DATE(FAIL_TIME, ''MM/DD/YY'') > 1/24;
IF v_count > 0 THEN
-- 알림 발송 로직 추가 (DBMS_ALERT 또는 UTL_MAIL 활용)
DBMS_OUTPUT.PUT_LINE(''In-Doubt 트랜잭션 감지: '' || v_count || ''건'');
END IF;
END;',
start_date => SYSTIMESTAMP,
repeat_interval => 'FREQ=MINUTELY;INTERVAL=30',
enabled => TRUE,
comments => 'In-Doubt 분산 트랜잭션 모니터링'
);
END;
/
2. 락 대기 임계값 설정 및 애플리케이션 트랜잭션 최적화
애플리케이션에서 DML 트랜잭션을 가능한 짧게 유지하고, 장시간 실행되는 트랜잭션은 분할 처리(Chunking)하는 방식으로 락 보유 시간을 최소화해야 합니다. DDL_LOCK_TIMEOUT 및 LOCK_TIMEOUT 관련 파라미터를 업무 특성에 맞게 설정하고, SELECT ... FOR UPDATE WAIT n 구문을 활용하여 무한정 대기하는 상황을 방지하는 코딩 표준을 수립하는 것이 효과적입니다.
-- 애플리케이션에서 명시적 락 타임아웃 설정 예시
-- WAIT n: n초 동안 대기 후 ORA-30006 발생 (무한 대기 방지)
SELECT employee_id, salary
FROM employees
WHERE department_id = 10
FOR UPDATE WAIT 5;
-- DDL_LOCK_TIMEOUT 설정 (DDL 작업 시 락 대기 시간)
ALTER SESSION SET DDL_LOCK_TIMEOUT = 30;
관련 에러
- ORA-00050:
operating system error occurred while obtaining enqueue– 운영체제 레벨의 큐 리소스 획득 실패로 ORA-00051과 함께 발생할 수 있습니다. - ORA-02049:
timeout: distributed transaction waiting for lock– 분산 트랜잭션 환경에서 락 대기 타임아웃이 발생했을 때 나타나며, ORA-00051과 매우 밀접한 관계를 가집니다. - ORA-04021:
timeout occurred while waiting to lock object– 특정 오브젝트에 대한 락 획득 타임아웃으로, DDL 수행 시 자주 발생합니다. - ORA-30006:
resource busy; acquire with WAIT timeout expired–SELECT FOR UPDATE WAIT n구문에서 n초 초과 시 발생하는 에러로 개발자가 자주 접하는 관련 에러입니다. - ORA-00060:
deadlock detected while waiting for resource– 두 세션이 서로의 리소스를 대기하는 교착상태로, 락 경합이 극단화된 형태이며 ORA-00051 발생 환경과 유사한 조건에서 나타납니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.