"MView와 View는 같은 View인데 어떻게 다를까?"
CREATE MATERIALIZED VIEW LOG ON MY_DB_TABLE
-- PRIMARY KEY : 데이터 식별 값을 로그에 포함
-- SEQUENCE : 변경 사항이 발생할 때마다 순차 번호 부여
-- ROWID : Oracle 데이터베이스에서 특정 행(row)의 물리적인 위치를 나타내는 고유한 식별자(디스크의 어느 블록(Block)에 위치하는지를 식별하는 값 ; 16바이트) : 빠른 행 식별 및 갱신
WITH PRIMARY KEY, ROWID, SEQUENCE
-- INCLUDING NEW VALUES : 갱신된 데이터 저장 (새로운 값이 저장됨)
-- INCLUDING NEW VALUES 생략될 경우 : LOG에는 보통 ROWID랑 PRIMARY KEY 등만 저장되어 MView 갱신 시 신규 값들을 다시 원본테이블에서 조회해야 함 (FAST REFRESH ; 빠른 갱신을 효율적으로 이용하려면 필수)
INCLUDING NEW VALUES;
-- WITH 뒤에 오는 것은 로그의 설정 값이라고 보면 된다.
-- 이외에도 설정할 수 있는 값이 많음.
CREATE MATERIALIZED VIEW <Materialized_View명>
[BUILD IMMEDIATE] or [BUILD DEFERRED]
REFRESH
[FORCE] or [COMPLETE] or [FAST] or [NEVER]
[ON DEMAND] or [ON COMMIT]
[ENABLE QUERY REWRITE] or [DISABLE QUERY REWRITE]
AS [SELECT 쿼리문]
-- 1.
CREATE MATERIALIZED VIEW MV_CTEST1
REFRESH FAST ON COMMIT -- 원본 테이블이 변경될때(커밋될 떄) 마다 변경된 데이터만
AS
SELECT * FROM X_MV_TABLE_TEST;
-- 2.
CREATE MATERIALIZED VIEW MV_CTEST2
REFRESH COMPLETE -- 데이터 전체 갱신
START WITH SYSDATE
NEXT TRUNC(SYSDATE + 1) + 6/24 -- 새벽 6시 마다
AS
SELECT * FROM X_MV_TABLE_TEST;
"왜 INNER JOIN은 모니터링하는데 어려움이 있을까?"
- 매칭안되는 건에 대해 추적이 불가능할 때가 있다. (데이터 일관성이 깨져버림)
"왜 OUTER JOIN은 변경 사항을 추적하는데 복잡할까?"
- NULL이 어떤 의미의 NULL인지 추적하기 어렵다.
oracle 11g 환경에서 MView를 생성하려고 했을 때 ON COMMIT 옵션을 넣게되면 'ORA-12054: 구체화된 뷰에 ON COMMIT 재생 속성을 설정할 수 없습니다.' 이라는 에러가 발생해 생성할 수 없었다.
사용하는 쿼리가 너무 복잡하거나 집계 함수, 서브쿼리가 포함된 경우엔 FAST REFRESH가 안될 수 있다. 그렇기 때문에 ON COMMIT 또한 사용하지 못한다.
-- 단순한 쿼리로 진행 (실패)
CREATE MATERIALIZED VIEW MV_STAT_ORG
BUILD IMMEDIATE
REFRESH FAST ON COMMIT
AS
SELECT NAME, AGE
FROM ORG_TABLE; -- 기존 테이블
-- 간단한 테이블을 하나 생성해서 진행 (성공)
CREATE MATERIALIZED VIEW X_MV_TABLE_CREATE
BUILD IMMEDIATE
REFRESH FAST ON COMMIT
AS
SELECT ID, NAME, AGE
FROM X_MV_TABLE_TEST; -- 새로 생성한 테이블
ON COMMIT을 설정할 때 PRIMARY KEY가 있어야 FAST REFRESH를 지원한다. PRIMARY KEY나 UNIQUE KEY가 없는 경우 ON COMMIT이 작동하지 않을 수 있다.
환경 문제로 Oracle 11g에서 ON COMMIT은 지원되지만, 특정 환경 설정이나 제한이 있을 수도 있다.
MView의 생성과 갱신을 위한 권한이 부족할 경우 ON COMMIT이 정상적으로 작동하지 않을 수 있다.
-- 테이블 소유자 확인 (소유자인 것으로 나옴)
SELECT * FROM ALL_TAB_PRIVS WHERE TABLE_NAME = '테이블명';
-- 테이블 권한 설정 (소유자이더라도 MView의 ON COMMIT REFRESH**를 사용할 때는 추가적인 권한이 필요할 수 있어 설정 완료)
GRANT QUERY REWRITE TO 소유자명;
GRANT CREATE MATERIALIZED VIEW TO 소유자명;
Materialized View log가 없는 경우 생성되지 않을 수 있다.
-- 로그 테이블은 생성된걸로 확인이 되었다.
SELECT * FROM user_mview_logs WHERE master = '로그를 생성한 테이블명';
FAST REFRESH 지원 여부에 따라 ON COMMIT이 안될 수 있다.
CREATE TABLE mv_capabilities_table AS
SELECT * FROM TABLE(DBMS_MVIEW.EXPLAIN_MVIEW('YOUR_MVIEW_NAME'));
-- 위의 CREATE문 실행 권한이 없을 경우 권한 확인
SELECT * FROM USER_TAB_PRIVS WHERE TABLE_NAME = 'DBMS_MVIEW';
-- 쿼리의 결과가 비어있는 경우 권한 부여
GRANT EXECUTE ON DBMS_MVIEW TO 조회하고자하는사용자명;
-- 위의 절차를 따랐음에도 ORA-01031: 권한이 불충분합니다. 뜨는 경우는 DBA 사용자에게 위의 GRANT 쿼리문을 요청하여야 함.
-- Capability_name이 FAST인 지원 여부 확인
SELECT capability_name, possible, related_text, msgtxt
FROM mv_capabilities_table
WHERE possible = 'NO';
해당 테이블이 분산 환경의 경우이면 ON COMMIT이 안될 수 있다.
기본 테이블이 여러 계정에 의해 참조되는 경우 ON COMMIT이 제한이 있을 수 있음
SDO_GEMETRY와 관련된 도메인 인덱스가 있는 경우 ON COMMIT 방식의 MView를 생성할 수 없음
여기서 의문!
Q. MView를 생성할때 조회 컬럼에 SDO_GEMETRY 컬럼을 포함하지 않는데 왜 안될까?
A. 원본 테이블의 도메인 때문! MView는 참조하는 원본 테이블의 인덱스와 제약조건을 함께 고려함.
원본 테이블이 SDO_GEMETRY 컬럼을 가지고 있고 이 컬럼에 대한 SPATIAL_INDEX(도메인 인덱스)도 가지고 있으니 ON COMMIT을 사용하지 못하게 된 것! 해당 컬럼에 대해 자동 갱신을 보장할 수 없기 때문
Q. 도메인 인덱스가 뭐길래 왜 ON COMMIT을 막아?
A. 차근차근 설명해보자면...
- MView의 ON COMMIT 방식으로 원본 테이블이 변경되어 커밋될 때 즉시 MView에 반영하는 구조.
- Oracle은 수행하기 위해 원본 테이블의 트랜잭션 로그를 활용해서 MView를 업데이트하는데... 도메인 인덱스는 트랜잭션 로그를 사용X
- 공간 데이터 인덱스는 배치 프로세스 또는 지연 업데이트 방식 또는 수동으로 명령어를 돌려서 갱신되는데 이 말은 즉, 트랜잭션 커밋될 때 즉시 변경 사항을 반영할 수 없다는 뜻
- 하지만 MView를 만들려면 원본 테이블이 모든 인덱스 변경을 트랜잭션 커밋 시점에 즉시 처리할 수 있어야 함 그렇기 때문에 ON COMMIT을 사용할 수 없음.
- Oracle은 "컬럼 단위 변경 추적"이 아니라, "테이블 단위 변경 추적"을 수행
- 조회하는 컬럼이 아니므로 영향이 없어야 할 것 같지만, 테이블 단위로 변경 사항을 감지하기 때문에 변경된 행이 MView 갱신 대상으로 포함되고 이 과정에서 테이블의 모든 인덱스가 연관된 트랜잭션에 포함되면서 문제가 생기는 것...
필자의 경우는 (9)번으로 인해 MView를 생성하지 못하는 경우가 있었지만 모두 해당되지 않는다면 MView를 사용하는 것도 도움이 될 것 같다.