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

ORA-12016
2026년 09월 05일 | DBMS Error 가이드

이 글에서 다루는 내용

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

ORA-12016 materialized view does not include all primary key columns 는?

ORA-12016 에러는 Materialized View(구체화 뷰)를 생성하거나 갱신할 때, 해당 뷰의 정의에 기반 테이블의 기본 키(Primary Key) 컬럼이 모두 포함되지 않았을 때 발생하는 에러입니다. Oracle은 Fast Refresh(빠른 갱신) 방식을 사용하는 Materialized View에서 기본 키를 기반으로 변경된 데이터를 추적하기 때문에, 기본 키 컬럼이 누락되면 정확한 데이터 동기화가 불가능합니다. 주로 REFRESH FAST 옵션을 사용하는 Materialized View를 생성할 때 SELECT 절에 기본 키 컬럼을 빠뜨렸거나, 기반 테이블의 기본 키 구성이 변경된 경우에 이 에러가 발생합니다.


주요 발생 원인

1. REFRESH FAST 옵션 사용 시 기본 키 컬럼 누락

Fast Refresh 방식은 Oracle이 변경된 행만 선택적으로 갱신하는 효율적인 방법으로, 이를 위해 반드시 기반 테이블의 기본 키 컬럼이 Materialized View의 SELECT 절에 포함되어 있어야 합니다. 기본 키가 복합 키(Composite Key)인 경우 구성 컬럼 중 하나라도 빠지면 이 에러가 발생하며, 이는 가장 흔하게 나타나는 원인입니다.

2. 기반 테이블의 기본 키 변경 후 Materialized View 미수정

운영 중인 시스템에서 기반 테이블의 기본 키 컬럼이 추가되거나 변경되었는데, 이와 연관된 Materialized View를 갱신하지 않은 경우 발생합니다. 특히 기존에 정상 동작하던 Materialized View가 갑자기 이 에러를 발생시키는 경우, 기반 테이블의 DDL 변경이 원인인 경우가 많으므로 반드시 확인이 필요합니다.

3. Materialized View Log(MV Log) 미생성 또는 잘못된 설정

Fast Refresh를 사용하려면 기반 테이블에 Materialized View Log가 반드시 생성되어 있어야 하며, 이 로그 역시 기본 키 정보를 포함해야 합니다. MV Log가 없거나 WITH PRIMARY KEY 옵션 없이 생성된 경우, Materialized View 생성 시 ORA-12016 에러와 함께 관련 에러가 연쇄적으로 발생할 수 있습니다.


해결 방법

원인 1 해결: 기본 키 컬럼을 SELECT 절에 명시적으로 포함

기반 테이블의 기본 키 컬럼이 무엇인지 먼저 확인한 후, Materialized View 정의에 해당 컬럼을 모두 포함시킵니다.

-- 기반 테이블의 기본 키 컬럼 확인
SELECT cols.column_name, cols.position
FROM all_constraints cons
JOIN all_cons_columns cols
  ON cons.constraint_name = cols.constraint_name
 AND cons.owner = cols.owner
WHERE cons.constraint_type = 'P'
  AND cons.table_name = 'ORDERS'
  AND cons.owner = 'SCOTT';

-- 잘못된 Materialized View 예시 (기본 키 컬럼 누락)
-- ORDERS 테이블의 기본 키: ORDER_ID, ORDER_DATE (복합 키)
CREATE MATERIALIZED VIEW mv_orders
REFRESH FAST ON COMMIT
AS
SELECT order_date, customer_id, total_amount  -- ORDER_ID 누락!
FROM orders;
-- ORA-12016 발생

-- 올바른 Materialized View 예시 (기본 키 컬럼 모두 포함)
CREATE MATERIALIZED VIEW mv_orders
REFRESH FAST ON COMMIT
AS
SELECT order_id, order_date, customer_id, total_amount  -- 기본 키 모두 포함
FROM orders;

원인 2 해결: 기반 테이블 기본 키 변경 후 Materialized View 재생성

기반 테이블의 기본 키가 변경된 경우, 기존 Materialized View를 삭제하고 변경된 기본 키를 모두 포함하여 재생성합니다.

-- 현재 Materialized View 정의 확인
SELECT mview_name, query
FROM user_mviews
WHERE mview_name = 'MV_ORDERS';

-- 기존 Materialized View 삭제
DROP MATERIALIZED VIEW mv_orders;

-- 변경된 기본 키를 반영하여 재생성
-- 예: ORDER_ID, ORDER_SEQ가 새로운 복합 기본 키인 경우
CREATE MATERIALIZED VIEW mv_orders
BUILD IMMEDIATE
REFRESH FAST ON COMMIT
ENABLE QUERY REWRITE
AS
SELECT o.order_id,
       o.order_seq,       -- 새로 추가된 기본 키 컬럼
       o.order_date,
       o.customer_id,
       o.total_amount
FROM orders o;

원인 3 해결: Materialized View Log 올바르게 생성

Fast Refresh를 위한 MV Log를 올바르게 생성하고, 기본 키를 포함하도록 설정합니다.

-- 기존 MV Log 확인
SELECT log_table, primary_key, rowid, sequence
FROM user_mview_logs
WHERE master = 'ORDERS';

-- 잘못된 MV Log 삭제
DROP MATERIALIZED VIEW LOG ON orders;

-- 올바른 MV Log 생성 (PRIMARY KEY 포함)
CREATE MATERIALIZED VIEW LOG ON orders
WITH PRIMARY KEY, ROWID, SEQUENCE
INCLUDING NEW VALUES;

-- MV Log 생성 후 Materialized View 생성
CREATE MATERIALIZED VIEW mv_orders
BUILD IMMEDIATE
REFRESH FAST ON COMMIT
AS
SELECT order_id, order_date, customer_id, total_amount
FROM orders;

-- Refresh 테스트
EXEC DBMS_MVIEW.REFRESH('MV_ORDERS', 'F');

COMPLETE REFRESH로 우회하는 방법

Fast Refresh가 반드시 필요하지 않은 경우, Complete Refresh로 변경하여 즉시 문제를 해결할 수 있습니다.

-- Complete Refresh 방식으로 변경 (기본 키 컬럼 불필요)
CREATE MATERIALIZED VIEW mv_orders_complete
BUILD IMMEDIATE
REFRESH COMPLETE ON DEMAND
AS
SELECT order_date, customer_id, total_amount
FROM orders;

-- 수동으로 Complete Refresh 실행
EXEC DBMS_MVIEW.REFRESH('MV_ORDERS_COMPLETE', 'C');

예방 방법

1. Materialized View 생성 전 표준화된 체크리스트 적용

Materialized View를 생성하기 전, 항상 기반 테이블의 기본 키 구성을 먼저 조회하고 SELECT 절에 포함 여부를 확인하는 체크리스트를 팀 내 표준으로 만들어야 합니다. 특히 복합 기본 키를 사용하는 테이블을 대상으로 할 때는, 아래와 같이 스크립트를 통해 누락 여부를 자동으로 검증하는 절차를 CI/CD 파이프라인이나 배포 프로세스에 포함시키는 것이 효과적입니다.

-- MV 생성 전 기본 키 포함 여부 자동 검증 쿼리 예시
SELECT a.column_name AS pk_column,
       CASE WHEN b.column_name IS NOT NULL THEN 'INCLUDED' ELSE 'MISSING' END AS status
FROM (
    SELECT cols.column_name
    FROM all_constraints cons
    JOIN all_cons_columns cols
      ON cons.constraint_name = cols.constraint_name
    WHERE cons.constraint_type = 'P'
      AND cons.table_name = 'ORDERS'
) a
LEFT JOIN (
    SELECT column_name
    FROM all_mview_keys
    WHERE mview_name = 'MV_ORDERS'
) b ON a.column_name = b.column_name;

2. 기반 테이블 DDL 변경 시 연관 Materialized View 영향도 분석 의무화

운영 환경에서 테이블의 기본 키를 변경하거나 새로운 컬럼을 추가할 때, 반드시 해당 테이블을 참조하는 모든 Materialized View 목록을 사전에 조회하고 영향도를 분석해야 합니다. 아래 쿼리를 변경 관리 프로세스에 포함시켜, DDL 변경 전 영향받는 Materialized View를 자동으로 식별하도록 합니다.

-- 특정 테이블을 참조하는 모든 Materialized View 조회
SELECT mview_name, owner, refresh_method, last_refresh_date
FROM all_mviews
WHERE mview_name IN (
    SELECT mview_name
    FROM all_mview_detail_relations
    WHERE detailobj_name = 'ORDERS'
);

관련 에러

  • ORA-12015: FAST 갱신이 불가능한 Materialized View를 생성하려 할 때 발생하며, ORA-12016과 함께 자주 나타납니다.
  • ORA-23413: 테이블에 Materialized View Log가 없는 경우 발생하며, Fast Refresh 설정 시 ORA-12016과 연관되어 발생할 수 있습니다.
  • ORA-12054: ON COMMIT 갱신 옵션을 지원하지 않는 Materialized View에 해당 옵션을 설정할 때 발생합니다.
  • ORA-32401: Materialized View Log가 존재하지 않을 때 발생하는 에러로, MV Log 설정 과정에서 함께 확인이 필요합니다.

DBMS 에러 코드 시리즈

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

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

댓글 남기기