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

ORA-12034
2026년 09월 06일 | DBMS Error 가이드

이 글에서 다루는 내용

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

ORA-12034 materialized view log is younger than last refresh 는?

ORA-12034 에러는 Materialized View(구체화 뷰)를 Fast Refresh(빠른 새로 고침) 방식으로 갱신하려 할 때, Materialized View Log가 마지막 갱신 시점보다 더 최근에 생성되었거나 재생성된 경우 발생합니다. 쉽게 말해, Oracle이 증분 변경 데이터를 추적하던 로그 정보가 손실되거나 초기화되어, Fast Refresh에 필요한 이전 새로 고침 이후의 변경 이력을 더 이상 신뢰할 수 없는 상태가 된 것입니다. 이 에러가 발생하면 Fast Refresh는 불가능하며, 반드시 Complete Refresh(완전 새로 고침)를 수행하여 Materialized View를 재동기화해야 합니다.


주요 발생 원인

1. Materialized View Log의 삭제 후 재생성

가장 흔한 원인으로, DBA나 개발자가 기존 Materialized View Log를 DROP하고 다시 CREATE한 경우입니다. Log가 재생성되면 내부적으로 기록된 타임스탬프(SNAPTIME$$)가 초기화되어, Oracle은 “이 로그는 마지막 Refresh보다 더 나중에 만들어진 것”으로 인식하게 됩니다. 이 상태에서 Fast Refresh를 시도하면 즉시 ORA-12034가 발생합니다.

2. 기반 테이블(Master Table)의 DDL 변경으로 인한 Log 무효화

Materialized View Log가 설정된 기반 테이블에 ALTER TABLE로 컬럼 추가·삭제, 파티션 변경 등의 DDL 작업을 수행하면, 해당 Log가 내부적으로 무효화(Invalidated)되거나 자동으로 삭제 후 재생성되는 경우가 있습니다. 이처럼 DDL에 의한 Log 변경은 개발·운영 환경에서 빈번히 발생하며, 특히 야간 배포 시 Materialized View를 점검하지 않아 다음 날 새로 고침 실패로 이어지는 사례가 많습니다.

3. 데이터베이스 복구(Recovery) 또는 Export/Import 작업 후 타임스탬프 불일치

데이터베이스를 특정 시점으로 복구(Point-in-Time Recovery)하거나, 기반 테이블과 Materialized View를 서로 다른 시점에 Export/Import 했을 경우, Materialized View에 기록된 마지막 Refresh 시간과 Log의 생성 시간 사이에 불일치가 발생합니다. 특히 DataPump(impdp/expdp)로 테이블만 재이관하고 Materialized View Log는 별도로 처리하지 않은 경우, 이 에러가 빈번하게 발생합니다.


해결 방법

즉각적인 해결: Complete Refresh 수행

ORA-12034가 발생하면 Fast Refresh는 불가능합니다. 먼저 Complete Refresh로 Materialized View를 동기화합니다.

-- 단일 Materialized View Complete Refresh
EXEC DBMS_MVIEW.REFRESH('MV_SALES_SUMMARY', METHOD => 'C');

-- 여러 Materialized View 동시 Complete Refresh
EXEC DBMS_MVIEW.REFRESH(
    LIST    => 'MV_SALES_SUMMARY,MV_CUSTOMER_STATS,MV_PRODUCT_DAILY',
    METHOD  => 'C',
    ATOMIC_REFRESH => FALSE  -- 각각 독립적으로 처리하여 성능 향상
);

원인 1 해결: Materialized View Log 재생성 후 Complete Refresh

Log를 재생성해야 하는 경우, 반드시 아래 순서를 따릅니다.

-- Step 1: 기존 Log 삭제
DROP MATERIALIZED VIEW LOG ON SALES;

-- Step 2: Log 재생성 (필요한 컬럼 포함)
CREATE MATERIALIZED VIEW LOG ON SALES
    WITH ROWID, SEQUENCE (SALE_ID, PRODUCT_ID, SALE_DATE, AMOUNT)
    INCLUDING NEW VALUES;

-- Step 3: Complete Refresh 수행 (반드시 필요)
EXEC DBMS_MVIEW.REFRESH('MV_SALES_SUMMARY', METHOD => 'C');

-- Step 4: 이후 Fast Refresh 가능 여부 확인
SELECT MVIEW_NAME, LAST_REFRESH_TYPE, LAST_REFRESH_DATE, STALENESS
FROM   USER_MVIEWS
WHERE  MVIEW_NAME = 'MV_SALES_SUMMARY';

원인 2 해결: DDL 변경 후 복구 절차

기반 테이블에 DDL이 발생한 경우의 처리 방법입니다.

-- Materialized View Log 상태 확인
SELECT LOG_OWNER, MASTER, LOG_TABLE, LOG_TRIGGER, ROWIDS, PRIMARY_KEY,
       SEQUENCE, INCLUDE_NEW_VALUES
FROM   ALL_MVIEW_LOGS
WHERE  MASTER = 'SALES';

-- Materialized View의 현재 상태 점검
SELECT MVIEW_NAME, REFRESH_METHOD, REFRESH_MODE, LAST_REFRESH_DATE,
       COMPILE_STATE, STALENESS
FROM   USER_MVIEWS
WHERE  MVIEW_NAME = 'MV_SALES_SUMMARY';

-- Log가 자동 삭제된 경우 재생성 후 Complete Refresh
CREATE MATERIALIZED VIEW LOG ON SALES
    WITH PRIMARY KEY, ROWID
    INCLUDING NEW VALUES;

EXEC DBMS_MVIEW.REFRESH('MV_SALES_SUMMARY', 'C');

원인 3 해결: 타임스탬프 불일치 점검 및 수동 초기화

-- Materialized View Log의 SNAPTIME$$ 확인
-- (마지막 Refresh를 기록하는 내부 컬럼)
SELECT SNAPTIME$$, COUNT(*)
FROM   MLOG$_SALES   -- 실제 Log 테이블명: MLOG$_<마스터테이블명>
GROUP  BY SNAPTIME$$
ORDER  BY SNAPTIME$$;

-- USER_MVIEW_REFRESH_TIMES에서 마지막 Refresh 시간 확인
SELECT NAME, MASTER, LAST_REFRESH
FROM   USER_MVIEW_REFRESH_TIMES
WHERE  NAME = 'MV_SALES_SUMMARY';

-- 최종 해결: Complete Refresh로 타임스탬프 재동기화
EXEC DBMS_MVIEW.REFRESH('MV_SALES_SUMMARY', METHOD => 'C', ATOMIC_REFRESH => FALSE);

-- Refresh 후 상태 재확인
SELECT MVIEW_NAME, LAST_REFRESH_TYPE, LAST_REFRESH_DATE
FROM   USER_MVIEWS
WHERE  MVIEW_NAME = 'MV_SALES_SUMMARY';

Materialized View Refresh 상태 종합 점검 스크립트

현재 인스턴스의 모든 Materialized View 상태를 한번에 점검하는 쿼리입니다.

SELECT M.MVIEW_NAME,
       M.OWNER,
       M.REFRESH_METHOD,
       M.REFRESH_MODE,
       M.LAST_REFRESH_DATE,
       M.STALENESS,
       M.COMPILE_STATE,
       L.LOG_TABLE,
       L.SEQUENCE,
       -- Log 생성 시간이 마지막 Refresh보다 최신인지 확인
       CASE
           WHEN O.CREATED > M.LAST_REFRESH_DATE
           THEN '⚠ ORA-12034 위험: Log가 마지막 Refresh보다 최신'
           ELSE '✓ 정상'
       END AS LOG_STATUS
FROM   ALL_MVIEWS     M
JOIN   ALL_MVIEW_LOGS L ON M.OWNER = L.LOG_OWNER AND M.CONTAINER_NAME = L.MASTER
JOIN   ALL_OBJECTS    O ON O.OWNER = L.LOG_OWNER
                       AND O.OBJECT_NAME = L.LOG_TABLE
                       AND O.OBJECT_TYPE = 'TABLE'
WHERE  M.OWNER = USER
ORDER  BY LOG_STATUS DESC, M.MVIEW_NAME;

예방 방법

1. Materialized View Log 변경 시 반드시 Complete Refresh 자동화

운영 절차(Runbook)에 Materialized View Log를 DROP/CREATE하거나 기반 테이블에 DDL을 수행할 경우, 반드시 Complete Refresh를 후속 단계로 포함시켜야 합니다. 아래와 같이 DDL 작업 직후 즉시 Complete Refresh를 수행하는 스크립트를 배포 프로세스에 포함하면 에러를 원천적으로 차단할 수 있습니다.

-- 배포 스크립트 예시: DDL 후 자동 Complete Refresh
BEGIN
    -- 1. DDL 작업 수행 (예: 컬럼 추가)
    EXECUTE IMMEDIATE 'ALTER TABLE SALES ADD (DISCOUNT_RATE NUMBER(5,2))';

    -- 2. 관련 Materialized View Log 재생성
    EXECUTE IMMEDIATE 'DROP MATERIALIZED VIEW LOG ON SALES';
    EXECUTE IMMEDIATE '
        CREATE MATERIALIZED VIEW LOG ON SALES
        WITH PRIMARY KEY, ROWID, SEQUENCE
        (SALE_ID, PRODUCT_ID, SALE_DATE, AMOUNT, DISCOUNT_RATE)
        INCLUDING NEW VALUES';

    -- 3. 모든 관련 Materialized View Complete Refresh
    DBMS_MVIEW.REFRESH(
        LIST           => 'MV_SALES_SUMMARY,MV_SALES_DAILY',
        METHOD         => 'C',
        ATOMIC_REFRESH => FALSE
    );

    DBMS_OUTPUT.PUT_LINE('배포 완료: Materialized View 재동기화 성공');
EXCEPTION
    WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('오류 발생: ' || SQLERRM);
        RAISE;
END;
/

2. 정기적인 Materialized View 상태 모니터링 및 알림 설정

야간 배치나 스케줄러(DBMS_SCHEDULER)를 통해 주기적으로 모든 Materialized View의 상태를 점검하고, STALENESS가 NEEDS_COMPILE 또는 UNUSABLE이거나 Log 타임스탬프 불일치가 감지되면 관리자에게 자동 알림을 발송하는 모니터링 Job을 설정합니다. 특히 Fast Refresh 방식의 Materialized View는 Log 의존성이 높으므로 일별 점검을 권장합니다.

-- DBMS_SCHEDULER를 이용한 일별 상태 점검 Job 등록 예시
BEGIN
    DBMS_SCHEDULER.CREATE_JOB(
        JOB_NAME        => 'JOB_CHECK_MVIEW_HEALTH',
        JOB_TYPE        => 'PLSQL_BLOCK',
        JOB_ACTION      => '
            DECLARE
                V_COUNT NUMBER;
            BEGIN
                SELECT COUNT(*) INTO V_COUNT
                FROM   USER_MVIEWS
                WHERE  STALENESS IN (''NEEDS_COMPILE'', ''UNUSABLE'', ''UNDEFINED'')
                OR     COMPILE_STATE != ''VALID'';

                IF V_COUNT > 0 THEN
                    -- 실무에서는 UTL_MAIL 또는 모니터링 툴 연동
                    DBMS_OUTPUT.PUT_LINE(
                        ''[경고] 비정상 Materialized View 감지: '' || V_COUNT || ''건''
                    );
                END IF;
            END;',
        START_DATE      => SYSTIMESTAMP,
        REPEAT_INTERVAL => 'FREQ=DAILY; BYHOUR=7; BYMINUTE=0',
        ENABLED         => TRUE,
        COMMENTS        => 'Materialized View 일별 상태 점검'
    );
END;
/

관련 에러

  • ORA-12032: Materialized View의 ROWID를 사용한 Fast Refresh가 불가능할 때 발생하며, ORA-12034와 함께 나타나는 경우가 많습니다.
  • ORA-12033: Materialized View Log에 Primary Key 정보가 없어 Fast Refresh를 수행할 수 없을 때 발생합니다.
  • ORA-23420: Refresh Group의 갱신 간격이 잘못 설정되었을 때 발생하며, DBMS_REFRESH 패키지 사용 시 연관됩니다.
  • ORA-12057: Materialized View가 Master Site로부터 갱신될 수 없는 상태일 때 발생하며, 분산 환경에서 ORA-12034와 함께 나타날 수 있습니다.

DBMS 에러 코드 시리즈

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

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

댓글 남기기