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

ORA-01039
2026년 07월 01일 | DBMS Error 가이드

이 글에서 다루는 내용

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

ORA-01039 insufficient privileges on underlying objects of the view 는?

ORA-01039 에러는 뷰(View)를 통해 데이터를 조회하거나 DML 작업을 수행할 때, 해당 뷰의 기반이 되는 원본 테이블이나 객체에 대한 충분한 권한이 없을 경우 발생하는 에러입니다. 특히 뷰를 생성한 소유자와 뷰를 사용하는 사용자가 서로 다른 스키마에 속해 있을 때 자주 나타납니다. 이 에러는 단순히 뷰 자체에 대한 SELECT 권한만으로는 해결되지 않으며, 뷰 내부에서 참조하는 실제 테이블이나 뷰에 대한 권한도 함께 고려해야 합니다.


주요 발생 원인

1. 뷰 기반 객체에 대한 직접 권한 미부여

가장 흔한 원인으로, 뷰를 사용하는 사용자에게 뷰 자체에 대한 SELECT 권한은 있지만 뷰가 참조하는 베이스 테이블에 대한 권한이 없는 경우입니다. Oracle은 뷰를 통해 데이터를 조회할 때 내부적으로 베이스 테이블의 권한도 확인하는 경우가 있으며, 특히 EXPLAIN PLAN이나 컴파일 시점에 이 문제가 드러납니다. 이는 권한 체계가 복잡한 대규모 시스템에서 자주 발생합니다.

2. ROLE을 통해 부여된 권한으로 뷰 생성 시도

Oracle에서 뷰를 생성할 때 ROLE을 통해 간접적으로 부여된 권한은 인정되지 않고, 직접 GRANT된 권한만 유효합니다. 예를 들어 DBA ROLE을 가진 사용자가 다른 스키마의 테이블을 참조하는 뷰를 만들 때, 해당 테이블에 대한 직접 SELECT 권한이 없다면 이 에러가 발생할 수 있습니다. 이 경우 뷰 생성 자체는 성공하더라도 이후 사용 시 에러가 나타날 수 있습니다.

3. 중첩 뷰(View of View) 구조에서의 권한 누락

뷰 위에 또 다른 뷰를 생성하는 중첩 구조에서, 중간 단계의 뷰나 최하위 베이스 테이블에 대한 권한이 누락된 경우 발생합니다. 권한 체인이 중간에 끊기면 상위 뷰에 접근하려는 사용자가 ORA-01039를 경험하게 됩니다. 이런 구조는 대형 엔터프라이즈 환경에서 레이어별 보안 정책을 구현할 때 자주 사용되므로 특히 주의가 필요합니다.


해결 방법

원인 1 해결: 베이스 테이블에 직접 권한 부여

뷰를 사용하는 사용자 또는 뷰 소유자에게 베이스 테이블에 대한 직접 권한을 부여합니다.

-- 현재 뷰의 구조와 기반 테이블 확인
SELECT view_name, text
FROM dba_views
WHERE view_name = 'YOUR_VIEW_NAME';

-- 뷰의 기반 테이블 목록 확인
SELECT referenced_owner, referenced_name, referenced_type
FROM dba_dependencies
WHERE name = 'YOUR_VIEW_NAME'
  AND type = 'VIEW';

-- 베이스 테이블에 직접 SELECT 권한 부여
GRANT SELECT ON schema_owner.base_table_name TO target_user;

-- 여러 테이블에 권한 부여가 필요한 경우
GRANT SELECT ON hr.employees TO app_user;
GRANT SELECT ON hr.departments TO app_user;
GRANT SELECT ON hr.locations TO app_user;

원인 2 해결: ROLE 대신 직접 권한 부여

ROLE 기반 권한을 직접 GRANT 방식으로 전환합니다.

-- 현재 사용자의 권한 확인 (ROLE 포함)
SELECT * FROM session_privs;
SELECT * FROM user_sys_privs;
SELECT * FROM user_tab_privs;

-- ROLE을 통한 권한이 아닌 직접 권한 부여
-- 잘못된 방법: ROLE에 권한 부여 후 USER에 ROLE 부여
GRANT SELECT ON hr.employees TO hr_readonly_role;
GRANT hr_readonly_role TO view_owner; -- 이것만으로는 뷰 생성 시 불충분

-- 올바른 방법: 뷰 소유자에게 직접 권한 부여
GRANT SELECT ON hr.employees TO view_owner;
GRANT SELECT ON hr.departments TO view_owner;

-- 이후 뷰 생성
CREATE OR REPLACE VIEW view_owner.emp_dept_view AS
SELECT e.employee_id, e.first_name, e.last_name, d.department_name
FROM hr.employees e
JOIN hr.departments d ON e.department_id = d.department_id;

원인 3 해결: 중첩 뷰 권한 체인 점검

중첩 뷰 구조에서 권한 체인을 점검하고 누락된 권한을 보완합니다.

-- 뷰의 의존성 체인 전체 조회
SELECT level, referenced_owner, referenced_name, referenced_type
FROM dba_dependencies
START WITH name = 'TOP_LEVEL_VIEW'
  AND type = 'VIEW'
CONNECT BY PRIOR referenced_name = name
  AND PRIOR referenced_type = type;

-- 각 레이어별 권한 부여 예시
-- 1단계: 베이스 테이블 권한
GRANT SELECT ON base_schema.employees TO mid_schema;

-- 2단계: 중간 뷰에 대한 권한
GRANT SELECT ON mid_schema.emp_mid_view TO top_schema;

-- 3단계: 최종 사용자에게 최상위 뷰 권한 부여
GRANT SELECT ON top_schema.emp_top_view TO end_user;

-- WITH GRANT OPTION이 필요한 경우 (권한을 다시 부여할 수 있도록)
GRANT SELECT ON base_schema.employees TO mid_schema WITH GRANT OPTION;

권한 현황 종합 점검 스크립트

-- 특정 뷰에 대한 권한 현황 전체 확인
SELECT grantee, owner, table_name, privilege, grantable
FROM dba_tab_privs
WHERE table_name = 'YOUR_VIEW_NAME'
ORDER BY grantee;

-- 뷰 소유자가 가진 객체 권한 확인
SELECT owner, table_name, privilege, grantable
FROM dba_tab_privs
WHERE grantee = 'VIEW_OWNER'
ORDER BY owner, table_name;

-- 권한 문제 자가 진단 쿼리
SELECT 'MISSING GRANT' AS status,
       d.referenced_owner,
       d.referenced_name,
       d.referenced_type
FROM dba_dependencies d
WHERE d.name = 'YOUR_VIEW_NAME'
  AND d.type = 'VIEW'
  AND NOT EXISTS (
    SELECT 1 FROM dba_tab_privs p
    WHERE p.grantee = 'TARGET_USER'
      AND p.owner = d.referenced_owner
      AND p.table_name = d.referenced_name
      AND p.privilege = 'SELECT'
  );

예방 방법

1. 뷰 생성 전 권한 체크리스트 운영

뷰를 생성하기 전에 반드시 뷰 소유자가 모든 베이스 테이블에 직접 권한(ROLE 기반이 아닌)을 보유하고 있는지 확인하는 프로세스를 수립하세요. 특히 배포 전 단계에서 아래와 같은 스크립트를 실행하여 권한 누락 여부를 자동으로 점검하는 것이 좋습니다. DBA 팀과 개발 팀 간의 권한 부여 절차를 표준화하고 문서화하면 실수를 줄일 수 있습니다.

-- 뷰 생성 전 권한 사전 점검 프로시저 예시
BEGIN
  FOR r IN (
    SELECT referenced_owner, referenced_name
    FROM dba_dependencies
    WHERE name = 'NEW_VIEW_NAME' AND type = 'VIEW'
  ) LOOP
    DBMS_OUTPUT.PUT_LINE('Check grant: ' || r.referenced_owner || '.' || r.referenced_name);
  END LOOP;
END;
/

2. 스키마 설계 시 권한 모델 명문화

다중 스키마 환경에서는 어떤 스키마가 어떤 객체에 접근할 수 있는지를 권한 매트릭스로 문서화하고, 변경 시 반드시 리뷰 절차를 거치도록 하세요. 중첩 뷰 구조를 사용할 경우 최하위 테이블부터 최상위 뷰까지의 권한 흐름도를 유지 관리하면 장애 발생 시 빠르게 원인을 파악할 수 있습니다.


관련 에러

  • ORA-01031 (insufficient privileges): 뷰 기반 객체가 아닌 일반 객체에 대한 권한이 부족할 때 발생하며, ORA-01039와 혼동되기 쉬운 에러입니다.
  • ORA-00942 (table or view does not exist): 권한이 없거나 객체가 존재하지 않을 때 발생하며, 뷰의 베이스 테이블이 삭제된 경우에도 나타날 수 있습니다.
  • ORA-04063 (view has errors): 뷰 자체에 컴파일 오류가 있을 때 발생하며, 베이스 테이블 권한 변경 후 뷰가 INVALID 상태가 된 경우 함께 확인해야 합니다.
  • ORA-01720 (grant option does not exist for object): WITH GRANT OPTION 없이 받은 권한을 다시 다른 사용자에게 부여하려 할 때 발생합니다.

DBMS 에러 코드 시리즈

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

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

댓글 남기기