DBMS/Oracle

Oracle) ORA-04063 오류: 테이블 DROP & CREATE로 인한 View INVALID 원인과 해결

소소한 늙은 개발자의 메모장 2026. 9. 21. 11:45
반응형

Oracle을 운영하다 보면 View를 조회할 때 다음과 같은 오류가 발생하는 경우가 있다.

ORA-04063: view "SCHEMA.VIEW_NAME" has errors

특이한 점은 View 내부의 SELECT 쿼리를 직접 실행하면 정상적으로 조회되는데, View를 통해 조회할 때만 ORA-04063 오류가 발생하는 경우이다.

이러한 현상은 View가 참조하는 테이블을 주기적으로 DROP → CREATE하는 환경에서 발생할 수 있다.


1. 발생 현상

다음과 같은 View가 있다고 가정한다.

CREATE OR REPLACE VIEW V_SAMPLE AS
SELECT
    A.ID,
    A.NAME,
    B.VALUE
FROM TABLE_A A
JOIN TABLE_B B
    ON A.ID = B.ID;

그런데 다음 쿼리를 실행하면:

SELECT *
FROM V_SAMPLE;

아래와 같은 오류가 발생한다.

ORA-04063: view "SCHEMA.V_SAMPLE" has errors

하지만 View에 정의된 SELECT 문을 직접 실행하면 정상적으로 조회되는 경우가 있다.

SELECT
    A.ID,
    A.NAME,
    B.VALUE
FROM TABLE_A A
JOIN TABLE_B B
    ON A.ID = B.ID;

이 경우 SQL 문 자체보다는 View 객체의 상태와 종속성(Dependency)을 확인할 필요가 있다.


2. 원인

문제가 발생한 환경에서는 배치 또는 스케줄러가 외부 시스템에서 데이터를 가져와 테이블을 주기적으로 갱신하고 있었다.

갱신 방식은 다음과 유사하다.

DROP TABLE TABLE_B;

CREATE TABLE TABLE_B (
    ...
);

즉 기존 데이터를 수정하는 것이 아니라 기존 테이블을 삭제한 후 동일한 이름의 테이블을 다시 생성하는 방식이다.

여기서 중요한 점은 Oracle에서 기존 테이블을 DROP하고 같은 이름으로 다시 CREATE하더라도 종속 객체 입장에서는 단순한 데이터 갱신과 다르다는 것이다.

기존 구조:

V_SAMPLE (VIEW)
    │
    └── TABLE_B

TABLE_B를 DROP하면 기존 객체에 대한 종속성에 영향을 주게 된다.

TABLE_B DROP
    ↓
종속 객체 영향
    ↓
V_SAMPLE INVALID 가능

이후 같은 이름으로 다시 테이블을 생성하더라도 View가 정상적으로 재검증되지 못한 경우 ORA-04063이 발생할 수 있다.


3. View 상태 확인

먼저 View가 VALID인지 INVALID인지 확인한다.

SELECT
    OBJECT_NAME,
    OBJECT_TYPE,
    STATUS,
    LAST_DDL_TIME
FROM USER_OBJECTS
WHERE OBJECT_NAME = 'V_SAMPLE';

문제가 발생한 경우 다음과 같이 확인될 수 있다.

OBJECT_NAME    OBJECT_TYPE    STATUS
-------------  -------------  -------
V_SAMPLE       VIEW           INVALID

스키마 전체의 INVALID 객체를 확인하려면 다음과 같이 조회할 수 있다.

SELECT
    OBJECT_NAME,
    OBJECT_TYPE,
    STATUS,
    LAST_DDL_TIME
FROM USER_OBJECTS
WHERE STATUS = 'INVALID'
ORDER BY OBJECT_TYPE, OBJECT_NAME;

DBA 권한이 있다면 DBA_OBJECTS를 이용해 전체 스키마를 확인할 수도 있다.


4. View의 종속 객체 확인

어떤 객체를 참조하고 있는지는 USER_DEPENDENCIES를 통해 확인할 수 있다.

SELECT
    NAME,
    TYPE,
    REFERENCED_OWNER,
    REFERENCED_NAME,
    REFERENCED_TYPE
FROM USER_DEPENDENCIES
WHERE NAME = 'V_SAMPLE';

DBA 권한이 있다면 반대로 특정 테이블을 참조하는 객체도 확인할 수 있다.

SELECT
    OWNER,
    NAME,
    TYPE
FROM DBA_DEPENDENCIES
WHERE REFERENCED_OWNER = 'SCHEMA_NAME'
  AND REFERENCED_NAME  = 'TABLE_B'
ORDER BY TYPE, NAME;

이를 통해 해당 테이블의 DROP & CREATE 작업으로 영향을 받을 수 있는 View, Procedure, Function, Package 등을 확인할 수 있다.


5. 해결 방법

문제가 발생한 View를 다시 컴파일한다.

ALTER VIEW V_SAMPLE COMPILE;

재컴파일 후 상태를 확인한다.

SELECT
    OBJECT_NAME,
    OBJECT_TYPE,
    STATUS
FROM USER_OBJECTS
WHERE OBJECT_NAME = 'V_SAMPLE';

정상적으로 컴파일되었다면:

V_SAMPLE    VIEW    VALID

상태로 변경된다.

여러 View가 영향을 받는 구조라면 배치 작업 마지막에 관련 View를 재컴파일하도록 구성할 수도 있다.

BEGIN
    EXECUTE IMMEDIATE 'ALTER VIEW V_SAMPLE_A COMPILE';
    EXECUTE IMMEDIATE 'ALTER VIEW V_SAMPLE_B COMPILE';
    EXECUTE IMMEDIATE 'ALTER VIEW V_SAMPLE_C COMPILE';
END;
/

6. 테이블 자체도 재컴파일해야 할까?

필요하지 않다.

일반적인 Oracle Table은 View나 PL/SQL 객체처럼 재컴파일하는 객체가 아니다.

TABLE_B
  ↑
  ├─ VIEW
  ├─ PROCEDURE
  ├─ FUNCTION
  └─ PACKAGE

TABLE_BDROP → CREATE했다면 확인해야 하는 것은 테이블 자체가 아니라 TABLE_B를 참조하고 있던 종속 객체이다.

즉,

DROP TABLE
    ↓
CREATE TABLE
    ↓
데이터 적재
    ↓
종속 View 등 상태 확인
    ↓
필요한 객체 재컴파일

순서로 처리하면 된다.


7. DROP & CREATE 대신 사용할 수 있는 방법

테이블 구조가 동일하다면 가능하면 DROP → CREATE보다 기존 테이블 객체를 유지하는 방법이 안정적이다.

대표적인 방법이:

TRUNCATE → INSERT

또는:

MERGE

방식이다.

TRUNCATE + INSERT

TRUNCATE TABLE TABLE_B;

INSERT INTO TABLE_B
SELECT ...
FROM ...;

COMMIT;

기존 Table 객체를 유지하므로 View와의 종속성 관리 측면에서 DROP → CREATE보다 유리하다.

MERGE

기존 데이터와 신규 데이터를 비교하여 변경된 데이터를 반영해야 한다면 MERGE를 사용할 수도 있다.

MERGE INTO TABLE_B T
USING SOURCE_TABLE S
   ON (T.ID = S.ID)
WHEN MATCHED THEN
    UPDATE SET T.VALUE = S.VALUE
WHEN NOT MATCHED THEN
    INSERT (ID, VALUE)
    VALUES (S.ID, S.VALUE);

다만 외부 시스템과 연동하는 임시·동기화 테이블처럼 원본 테이블의 컬럼 구조가 변경될 가능성이 있는 경우에는 단순히 MERGE 방식으로 변경하기 어려울 수 있다.

이러한 환경에서는 DROP → CREATE를 유지하되 작업 완료 후 관련 종속 객체의 상태를 확인하고 필요한 View를 재컴파일하는 방법도 현실적인 운영 방법이 될 수 있다.


8. 배치 작업 개선

DROP → CREATE 방식을 계속 사용해야 한다면 배치 또는 Scheduler 작업을 다음과 같이 구성할 수 있다.

1. 기존 테이블 DROP
        ↓
2. 신규 테이블 CREATE
        ↓
3. 데이터 적재
        ↓
4. 데이터 검증
        ↓
5. 관련 View COMPILE
        ↓
6. INVALID 객체 확인
        ↓
7. 정상 종료

마지막 단계에서 INVALID 객체가 남아 있는지 확인한다.

SELECT
    OBJECT_NAME,
    OBJECT_TYPE,
    STATUS
FROM USER_OBJECTS
WHERE STATUS = 'INVALID';

이를 통해 사용자가 실제 업무 시스템에서 View를 호출하기 전에 문제를 발견할 수 있다.


9. 정리

이번 사례의 핵심은 SQL 자체의 오류와 Schema Object의 INVALID 상태를 구분해야 한다는 것이다.

View 내부 SELECT 문을 직접 실행했을 때 정상이라고 해서 해당 View 객체까지 정상이라고 볼 수는 없다.

특히 배치 작업에서 참조 테이블을 다음과 같이 관리한다면:

DROP TABLE
→ CREATE TABLE
→ INSERT

해당 테이블을 참조하는 View 등 종속 객체의 상태를 함께 확인할 필요가 있다.

가능하다면:

TRUNCATE + INSERT
MERGE

등 기존 Table 객체를 유지하는 구조가 종속성 관리 측면에서 더 안정적이다.

하지만 외부 시스템 연계 등으로 테이블 구조 자체가 변경될 가능성이 있어 DROP & CREATE가 불가피하다면,

DROP & CREATE
→ 데이터 적재
→ 종속 객체 재컴파일
→ INVALID 객체 검증

과정을 하나의 배치 작업으로 구성하는 것이 좋다.

결국 ORA-04063이 반복적으로 발생한다면 단순히 View를 수시로 재컴파일하기보다는 어떤 DDL 작업이 객체의 종속성을 무효화하고 있는지 확인하는 것이 우선이다.

 

 

※ 본 글은 시스템 운영중 발생한 오류를 분석후 ChatGPT 도움을 받아 작성하였습니다.

반응형