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

ORA-00604
2026년 06월 13일 | DBMS Error 가이드

이 글에서 다루는 내용

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

ORA-00604 error occurred at recursive SQL level 는?

ORA-00604는 Oracle 데이터베이스가 내부적으로 실행하는 재귀적 SQL(Recursive SQL) 처리 도중 오류가 발생했을 때 나타나는 에러입니다. 재귀적 SQL이란 사용자가 직접 실행하는 SQL이 아닌, Oracle 엔진이 데이터 딕셔너리 조회, 트리거 실행, 공간 관리 등을 위해 내부적으로 자동 실행하는 SQL을 의미합니다. 일반적으로 이 에러 단독으로 발생하기보다는 ORA-00942, ORA-01031, ORA-04098 등 다른 에러와 함께 스택 형태로 출력되며, 근본 원인은 함께 출력된 하위 에러 메시지에서 찾아야 합니다.


주요 발생 원인

1. 로그온/로그오프 트리거의 오류

가장 흔한 원인 중 하나로, 데이터베이스에 AFTER LOGON ON DATABASE 또는 BEFORE LOGOFF ON DATABASE 트리거가 설정되어 있을 때 해당 트리거 내부의 코드에 문제가 있으면 발생합니다. 예를 들어, 트리거가 참조하는 테이블이 삭제되었거나 권한이 변경된 경우, 또는 트리거 자체의 PL/SQL 로직에 버그가 있는 경우 모든 사용자의 로그인 시도마다 ORA-00604가 반복적으로 발생합니다. 이 경우 DBA 권한으로 접속하여 트리거를 즉시 비활성화하거나 수정해야 합니다.

2. 데이터 딕셔너리 손상 또는 권한 문제

Oracle이 내부 작업을 수행하기 위해 SYS 스키마의 데이터 딕셔너리 뷰나 테이블에 접근할 때 해당 객체가 손상되었거나 필요한 권한이 누락된 경우 발생할 수 있습니다. 특히 부주의한 패치 적용, 불완전한 업그레이드, 또는 SYS 객체를 직접 수정한 경우에 이 문제가 발생합니다. 데이터 딕셔너리의 무결성이 훼손된 경우에는 DBMS_METADATA 패키지 재컴파일 또는 utlrp.sql 스크립트 실행이 필요할 수 있습니다.

3. 잘못된 스키마 수준 트리거 또는 DDL 트리거

CREATE, DROP, ALTER 등의 DDL 이벤트에 반응하는 DDL 트리거나 특정 스키마에 종속된 트리거가 잘못 작성된 경우에도 ORA-00604가 발생합니다. 예를 들어 DDL 트리거 내에서 존재하지 않는 테이블에 감사 로그를 INSERT하려 할 때, 해당 테이블이 없으면 재귀 SQL 레벨에서 오류가 발생합니다. 이런 경우에는 해당 트리거를 찾아 비활성화한 후 원인을 분석해야 합니다.


해결 방법

원인 1 해결: 로그온 트리거 비활성화 및 수정

먼저 현재 존재하는 로그온/로그오프 트리거를 조회합니다.

-- 데이터베이스 레벨 트리거 조회
SELECT TRIGGER_NAME, TRIGGER_TYPE, TRIGGERING_EVENT, STATUS
FROM DBA_TRIGGERS
WHERE TRIGGERING_EVENT LIKE '%LOGON%'
   OR TRIGGERING_EVENT LIKE '%LOGOFF%';

문제가 되는 트리거를 비활성화합니다.

-- 트리거 비활성화 (SYSDBA 권한 필요)
ALTER TRIGGER SYS.LOGON_AUDIT_TRIGGER DISABLE;

-- 또는 특정 스키마의 모든 트리거 비활성화
ALTER TRIGGER HR.MY_LOGON_TRIGGER DISABLE;

트리거 내용을 확인하고 오류를 수정합니다.

-- 트리거 소스 코드 확인
SELECT TEXT
FROM DBA_SOURCE
WHERE NAME = 'LOGON_AUDIT_TRIGGER'
  AND TYPE = 'TRIGGER'
ORDER BY LINE;

-- 트리거가 참조하는 테이블 존재 여부 확인
SELECT TABLE_NAME FROM DBA_TABLES WHERE TABLE_NAME = 'AUDIT_LOG';

-- 수정 후 트리거 재활성화
ALTER TRIGGER SYS.LOGON_AUDIT_TRIGGER ENABLE;

원인 2 해결: 무효화된 객체 재컴파일

-- 무효화된 객체 목록 조회
SELECT OWNER, OBJECT_NAME, OBJECT_TYPE, STATUS
FROM DBA_OBJECTS
WHERE STATUS = 'INVALID'
ORDER BY OWNER, OBJECT_TYPE, OBJECT_NAME;

-- 특정 스키마의 무효 객체 일괄 재컴파일
EXEC DBMS_UTILITY.COMPILE_SCHEMA(SCHEMA => 'HR', COMPILE_ALL => FALSE);

-- 전체 데이터베이스 무효 객체 재컴파일 (sqlplus에서 실행)
-- @$ORACLE_HOME/rdbms/admin/utlrp.sql

원인 3 해결: DDL 트리거 비활성화 및 원인 테이블 생성

-- DDL 트리거 목록 조회
SELECT TRIGGER_NAME, TRIGGERING_EVENT, STATUS, OWNER
FROM DBA_TRIGGERS
WHERE TRIGGERING_EVENT LIKE '%DDL%'
   OR TRIGGERING_EVENT LIKE '%CREATE%'
   OR TRIGGERING_EVENT LIKE '%DROP%';

-- 문제 DDL 트리거 비활성화
ALTER TRIGGER AUDIT_SCHEMA.DDL_AUDIT_TRG DISABLE;

-- 누락된 감사 테이블 생성
CREATE TABLE AUDIT_SCHEMA.DDL_AUDIT_LOG (
    LOG_ID        NUMBER GENERATED ALWAYS AS IDENTITY,
    EVENT_DATE    DATE DEFAULT SYSDATE,
    DB_USER       VARCHAR2(100),
    EVENT_TYPE    VARCHAR2(50),
    OBJECT_TYPE   VARCHAR2(50),
    OBJECT_NAME   VARCHAR2(128),
    CONSTRAINT PK_DDL_AUDIT PRIMARY KEY (LOG_ID)
);

-- 트리거 재활성화
ALTER TRIGGER AUDIT_SCHEMA.DDL_AUDIT_TRG ENABLE;

에러 스택에서 근본 원인 파악하기

-- alert log에서 에러 스택 확인 (뷰를 통한 조회)
SELECT ORIGINATING_TIMESTAMP, MESSAGE_TEXT
FROM V$DIAG_ALERT_EXT
WHERE MESSAGE_TEXT LIKE '%ORA-00604%'
   OR MESSAGE_TEXT LIKE '%recursive SQL%'
ORDER BY ORIGINATING_TIMESTAMP DESC
FETCH FIRST 20 ROWS ONLY;

-- 현재 세션의 에러 정보 확인
SELECT * FROM V$SESSION
WHERE STATUS = 'ACTIVE'
  AND USERNAME IS NOT NULL;

예방 방법

1. 트리거 생성 전 철저한 테스트 및 예외 처리 적용

로그온 트리거나 DDL 트리거는 데이터베이스 전체에 영향을 미치기 때문에 반드시 개발/테스트 환경에서 충분히 검증한 후 운영 환경에 적용해야 합니다. 특히 트리거 내부에는 반드시 EXCEPTION 블록을 포함하여 내부 오류가 발생하더라도 데이터베이스 접속 자체가 차단되지 않도록 방어 코드를 작성하는 것이 Best Practice입니다.

-- 안전한 로그온 트리거 작성 예시
CREATE OR REPLACE TRIGGER SAFE_LOGON_TRIGGER
AFTER LOGON ON DATABASE
BEGIN
    -- 실제 비즈니스 로직
    INSERT INTO AUDIT_SCHEMA.LOGIN_LOG(USER_NAME, LOGIN_TIME)
    VALUES (SYS_CONTEXT('USERENV','SESSION_USER'), SYSDATE);
    COMMIT;
EXCEPTION
    WHEN OTHERS THEN
        -- 에러 발생 시 로그인을 막지 않고 조용히 무시
        NULL;
END;
/

2. 정기적인 데이터베이스 헬스 체크 및 무효 객체 모니터링

운영 환경에서는 주기적으로 무효화된 객체와 비활성 트리거를 점검하는 모니터링 쿼리를 스케줄링하고, Oracle DBMS_SCHEDULER를 활용하여 자동으로 재컴파일을 시도하는 유지보수 Job을 설정해 두는 것이 좋습니다. 패치 적용이나 업그레이드 후에는 반드시 utlrp.sql을 실행하여 무효 객체를 정리하는 절차를 표준 운영 프로세스로 수립해야 합니다.


관련 에러

  • ORA-00942: table or view does not exist — 트리거가 참조하는 테이블이 없을 때 ORA-00604와 함께 자주 발생합니다.
  • ORA-01031: insufficient privileges — 트리거 실행 계정에 권한이 없을 때 재귀 SQL 레벨에서 함께 출력됩니다.
  • ORA-04098: trigger is invalid and failed re-validation — 트리거 자체가 무효 상태일 때 ORA-00604와 쌍으로 발생하는 대표적인 에러입니다.
  • ORA-00600: internal error code — 데이터 딕셔너리 수준의 심각한 내부 오류 시 ORA-00604와 함께 나타날 수 있으며, Oracle Support 케이스 오픈이 필요합니다.
  • ORA-04031: unable to allocate memory — SGA 메모리 부족으로 내부 재귀 SQL 실행에 실패할 경우 동반 출력될 수 있습니다.

DBMS 에러 코드 시리즈

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

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

댓글 남기기