2026년 10월 13일 | DBMS Error 가이드
이 글에서 다루는 내용
ORA-65020 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
ORA-65020 pluggable database is already open 는?
ORA-65020 에러는 Oracle Multitenant 아키텍처에서 이미 열려(OPEN) 있는 Pluggable Database(PDB)를 다시 열려고 시도할 때 발생하는 에러입니다. CDB(Container Database) 환경에서 PDB의 상태를 정확히 확인하지 않고 ALTER PLUGGABLE DATABASE ... OPEN 명령을 반복 실행하거나, 자동화 스크립트에서 PDB 상태 체크 없이 OPEN 명령을 수행할 때 주로 발생합니다. 이 에러 자체는 데이터 손상이나 심각한 장애를 유발하지는 않지만, 운영 스크립트나 자동화 파이프라인에서 예외 처리가 미흡할 경우 후속 작업이 중단될 수 있으므로 반드시 원인을 파악하고 방지 로직을 적용해야 합니다.
주요 발생 원인
1. PDB 상태 확인 없이 OPEN 명령 중복 실행
가장 흔한 원인으로, DBA나 자동화 스크립트가 PDB의 현재 상태를 조회하지 않고 무조건 ALTER PLUGGABLE DATABASE OPEN 명령을 실행하는 경우입니다. 특히 데이터베이스 재시작 후 PDB를 자동으로 열어주는 스크립트에서 이미 OPEN 상태인 PDB에 대해 OPEN 명령을 재시도할 때 빈번하게 발생합니다. 여러 DBA가 동일한 환경에 접근하는 팀 운영 환경에서는 누군가 이미 PDB를 열었는데 다른 담당자가 중복으로 실행하는 상황도 자주 있습니다.
2. CDB 레벨에서 ALL 옵션을 사용한 일괄 OPEN 시도
ALTER PLUGGABLE DATABASE ALL OPEN 명령은 CDB 내의 모든 PDB를 한꺼번에 열 때 사용하는 명령인데, 이미 일부 PDB가 OPEN 상태에 있을 경우 해당 PDB에 대해 ORA-65020 에러가 발생할 수 있습니다. 이 명령은 RAC(Real Application Clusters) 환경이나 Data Guard 환경에서 Standby PDB의 상태 관리 시에도 잘못 사용되어 에러를 유발합니다. 특히 운영 환경에서 유지보수 작업 후 모든 PDB를 일괄 기동할 때 상태를 미리 점검하지 않으면 이 에러가 반드시 발생합니다.
3. 트리거 또는 자동화 작업에 의한 이중 실행
Oracle 데이터베이스에는 AFTER STARTUP 트리거를 이용하여 CDB 기동 시 PDB를 자동으로 열도록 설정하는 경우가 많습니다. 만약 트리거와 별도의 DBA 수동 작업이 동시에 실행되거나, 동일한 PDB OPEN 로직이 중복 정의된 트리거가 존재할 경우 ORA-65020이 발생합니다. 또한 Oracle Enterprise Manager(OEM)나 외부 스케줄링 도구(Cron, Ansible 등)에서 PDB 기동 Job이 중복 등록되어 있을 때도 이 에러가 반복적으로 나타납니다.
해결 방법
해결책 1: PDB 상태 사전 확인 후 조건부 OPEN
PDB를 열기 전에 반드시 현재 상태를 조회하고, MOUNTED 또는 CLOSED 상태일 때만 OPEN 명령을 실행하도록 합니다.
-- 현재 PDB 상태 조회
SELECT name, open_mode, restricted
FROM v$pdbs
ORDER BY name;
-- 특정 PDB의 상태 확인
SELECT name, open_mode
FROM v$pdbs
WHERE name = 'MY_PDB';
-- PL/SQL을 활용한 조건부 OPEN (실무 권장)
DECLARE
v_open_mode VARCHAR2(20);
BEGIN
SELECT open_mode
INTO v_open_mode
FROM v$pdbs
WHERE name = 'MY_PDB';
IF v_open_mode != 'READ WRITE' THEN
EXECUTE IMMEDIATE 'ALTER PLUGGABLE DATABASE MY_PDB OPEN';
DBMS_OUTPUT.PUT_LINE('MY_PDB가 성공적으로 OPEN되었습니다.');
ELSE
DBMS_OUTPUT.PUT_LINE('MY_PDB는 이미 OPEN 상태입니다. 작업을 건너뜁니다.');
END IF;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('에러 발생: ' || SQLERRM);
END;
/
해결책 2: ALL 옵션 사용 시 에러 무시 처리
운영 환경에서 ALL 옵션으로 일괄 OPEN할 경우, 이미 OPEN된 PDB에 대한 에러를 안전하게 처리합니다.
-- 모든 PDB 일괄 OPEN (이미 열린 PDB는 에러 발생 가능)
ALTER PLUGGABLE DATABASE ALL OPEN;
-- 더 안전한 방법: MOUNTED 상태인 PDB만 선택적으로 OPEN
BEGIN
FOR pdb_rec IN (
SELECT name
FROM v$pdbs
WHERE open_mode = 'MOUNTED'
AND name != 'PDB$SEED'
) LOOP
BEGIN
EXECUTE IMMEDIATE 'ALTER PLUGGABLE DATABASE ' || pdb_rec.name || ' OPEN';
DBMS_OUTPUT.PUT_LINE(pdb_rec.name || ' OPEN 성공');
EXCEPTION
WHEN OTHERS THEN
-- ORA-65020은 이미 열려있음을 의미하므로 무시
IF SQLCODE = -65020 THEN
DBMS_OUTPUT.PUT_LINE(pdb_rec.name || ' 이미 OPEN 상태 - 건너뜀');
ELSE
DBMS_OUTPUT.PUT_LINE(pdb_rec.name || ' OPEN 실패: ' || SQLERRM);
END IF;
END;
END LOOP;
END;
/
해결책 3: STARTUP TRIGGER 점검 및 중복 제거
기존에 설정된 STARTUP 트리거를 조회하고 중복 여부를 확인합니다.
-- 현재 등록된 DB 레벨 트리거 조회
SELECT trigger_name, trigger_type, triggering_event, status
FROM dba_triggers
WHERE triggering_event LIKE '%STARTUP%'
ORDER BY trigger_name;
-- 기존 트리거 비활성화
ALTER TRIGGER startup_open_pdbs DISABLE;
-- 안전한 STARTUP 트리거 재작성 (중복 방지 로직 포함)
CREATE OR REPLACE TRIGGER open_pdbs_on_startup
AFTER STARTUP ON DATABASE
DECLARE
v_open_mode VARCHAR2(20);
BEGIN
FOR pdb_rec IN (
SELECT name, open_mode
FROM v$pdbs
WHERE name != 'PDB$SEED'
) LOOP
IF pdb_rec.open_mode != 'READ WRITE' THEN
EXECUTE IMMEDIATE 'ALTER PLUGGABLE DATABASE '
|| pdb_rec.name || ' OPEN';
END IF;
END LOOP;
END;
/
-- 트리거 활성화 확인
SELECT trigger_name, status
FROM dba_triggers
WHERE trigger_name = 'OPEN_PDBS_ON_STARTUP';
해결책 4: READ ONLY 또는 RESTRICTED 모드로 OPEN된 경우 처리
PDB가 READ ONLY 또는 RESTRICTED 모드로 열려 있을 때 READ WRITE로 변경하려면 별도의 절차가 필요합니다.
-- PDB 상태 상세 확인
SELECT name, open_mode, restricted
FROM v$pdbs;
-- READ ONLY로 열린 PDB를 READ WRITE로 변경하려면 먼저 닫고 다시 열어야 함
ALTER PLUGGABLE DATABASE MY_PDB CLOSE IMMEDIATE;
ALTER PLUGGABLE DATABASE MY_PDB OPEN READ WRITE;
-- 또는 RESTRICTED 모드 해제
ALTER PLUGGABLE DATABASE MY_PDB OPEN READ WRITE;
-- (이미 열려있으면 ORA-65020 발생 → 닫고 재시작 필요)
예방 방법
1. PDB OPEN 스크립트에 상태 체크 로직 필수 포함
모든 PDB 기동 스크립트에는 사전에 v$pdbs 뷰를 조회하여 현재 상태를 확인하는 로직을 반드시 포함시켜야 합니다. 단순히 OPEN 명령만 실행하는 스크립트는 운영 환경에서 절대 사용하지 않도록 팀 내 코드 리뷰 프로세스를 적용하고, PL/SQL의 예외 처리 블록에서 ORA-65020(SQLCODE = -65020)을 명시적으로 처리하여 비정상 종료를 방지해야 합니다. 또한, SAVE STATE 옵션을 활용하면 CDB 재기동 시 PDB의 이전 상태가 자동으로 복원되어 수동 OPEN 작업 자체를 줄일 수 있습니다.
-- PDB의 현재 OPEN 상태를 자동 저장 (CDB 재시작 시 자동 복원)
ALTER PLUGGABLE DATABASE MY_PDB SAVE STATE;
-- 모든 PDB에 SAVE STATE 적용
ALTER PLUGGABLE DATABASE ALL SAVE STATE;
-- 저장된 상태 확인
SELECT con_name, state
FROM dba_pdb_saved_states;
2. 운영 환경 PDB 상태 모니터링 자동화
정기적으로 PDB 상태를 모니터링하는 스크립트를 DBMS_SCHEDULER Job으로 등록하여 비정상 상태의 PDB를 즉시 감지하고 알림을 발송하는 체계를 구축합니다. 이를 통해 PDB가 예기치 않게 CLOSED나 RESTRICTED 상태가 되었을 때 신속하게 대응할 수 있으며, 불필요한 중복 OPEN 시도 자체를 예방할 수 있습니다.
-- PDB 상태 모니터링 Job 생성
BEGIN
DBMS_SCHEDULER.CREATE_JOB(
job_name => 'JOB_MONITOR_PDB_STATUS',
job_type => 'PLSQL_BLOCK',
job_action => '
BEGIN
FOR r IN (
SELECT name, open_mode
FROM v$pdbs
WHERE name != ''PDB$SEED''
AND open_mode != ''READ WRITE''
) LOOP
-- 알림 또는 로그 기록 로직 추가
DBMS_OUTPUT.PUT_LINE(
r.name || '' is in '' || r.open_mode || '' mode''
);
END LOOP;
END;',
start_date => SYSTIMESTAMP,
repeat_interval => 'FREQ=MINUTELY;INTERVAL=10',
enabled => TRUE,
comments => 'PDB 상태 주기적 모니터링'
);
END;
/
관련 에러
- ORA-65019: pluggable database is not open — PDB가 열려있지 않은 상태에서 해당 PDB에 접근하려 할 때 발생하며, ORA-65020과 반대 상황입니다.
- ORA-65011: Pluggable database does not exist — 존재하지 않는 PDB 이름으로 OPEN 또는 CLOSE를 시도할 때 발생합니다.
- ORA-01109: database not open — CDB 자체가 열려있지 않을 때 발생하는 에러로, PDB OPEN 전에 CDB 상태를 먼저 확인해야 합니다.
- ORA-65054: Cannot open a pluggable database in the desired mode — PDB를 원하는 모드(READ WRITE/READ ONLY)로 열 수 없을 때 발생하며, Data Guard 환경의 Standby에서 자주 나타납니다.
- ORA-65099: pluggable database is not in MIGRATE mode — PDB 업그레이드 또는 마이그레이션 작업 중 모드 불일치로 발생합니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.