본 장에서는 Tibero에서 제공하는 실체화 뷰를 사용하는 방법에 대해 기술한다.
마스터 테이블에 변경이 일어났을 때 이를 반영하도록 실체화 뷰를 갱신하는 동작을 리프레시라고 한다. 리프레시를 하면 실체화 뷰의 데이터는 질의의 결과와 일치된다. 리프레시는 실체화 뷰를 생성하는 조건에 따라 자동으로 수행될 수 있으며, DBMS_MVIEW 패키지의 REFRESH 함수를 이용하여 수동으로 수행할 수도 있다.
리프레시는 완전 리프레시와 빠른 리프레시가 있다.
완전 리프레시는 실체화 뷰에 있는 기존의 데이터를 모두 삭제한 후 실체화 뷰를 정의한 질의를 다시 수행하여 그 결과를 실체화 뷰에 저장하는 방식이다. 완전 리프레시를 사용하기 위한 특별한 제약조건은 없다.
빠른 리프레시는 마스터 테이블의 변경된 부분만을 실체화 뷰에 반영하는 방식이다. 완전 리프레시보다 빠르다.
빠른 리프레시를 사용하기 위한 제약조건은 다음과 같다. 실체화 뷰를 정의하는 질의는 다음의 제약조건을 만족해야 한다.
실체화 뷰는 SYSDATE와 ROWNUM과 같이 반복할 수 없는 표현식을 포함하면 안 된다.
실체화 뷰는 LONG 또는 LONG RAW 데이터 타입을 포함하면 안 된다.
SELECT 리스트에 부질의를 포함하면 안 된다.
SELECT 리스트에 분석 함수를 포함하면 안 된다.
HAVING 절에 부질의를 포함하면 안 된다.
ANY, ALL, NOT EXISTS를 포함하면 안 된다.
[START WITH] CONNECT BY 절을 포함하면 안 된다.
서로 다른 원격에 있는 테이블을 포함하면 안 된다(즉 쿼리에 참가하는 모든 테이블은 같은 서버에 있어야 한다).
원격 테이블이 포함된 경우 해당 서버가 Tibero일 경우만 된다.
UNION 등의 SET 연산자를 포함하면 안 된다.
REFRESH ON COMMIT 실체화 뷰를 정의한 질의는 원격 테이블을 포함하면 안 된다.
빠른 리프레시의 일반적인 제약조건을 모두 포함한다.
실체화 뷰의 모든 참조 테이블에는 실체화 뷰의 로그가 있어야 하며, 실체화 뷰의 로그는 다음의 제약조건을 만족해야 한다.
실체화 뷰에서 참조하는 모든 컬럼을 포함해야 한다.
SEQUENCE, ROWID와 INCLUDING NEW VALUES 조건이 있어야 한다.
함수는 SUM, COUNT, AVG, STDDEV, VARIANCE, MIN, MAX 함수만 지원된다.
COUNT(*)는 항상 포함해야 한다.
집합 함수는 항상 표현식의 최상위에 있어야 한다. 단, AVG(COUNT(X)), COUNT(X) * COUNT(X)는 허용하지 않는다.
AVG(expr)에 대응되는 COUNT(expr)가 있어야 한다.
집단 함수 | 필요 집단 함수 |
---|---|
COUNT(expr) | - |
MIN(expr) | - |
MAX(expr) | - |
SUM(expr) | COUNT(expr) |
SUM(col), col에 NOT NULL 제약 | - |
AVG(expr) | COUNT(expr) |
STDDEV(expr) | SUM(expr), COUNT(expr) |
VARIANCE(expr) | SUM(expr), COUNT(expr) |
SELECT 리스트에는 모든 GROUP BY 컬럼이 있어야 한다.
CUBE, ROLLUP은 허용하지 않는다.
실체화 뷰의 가장 큰 장점은 질의 다시 쓰기(Query Rewrite) 기능을 사용할 수 있다는 것이다.
질의 다시 쓰기는 주어진 질의를 분석한 후 실체화 뷰를 사용하여 동일한 결과를 내는 새로운 질의를 생성하는 기능이다. 실체화 뷰가 복잡한 조인이나 집단 함수의 결과로 정의되어 있다면 질의 다시 쓰기를 통해 실행 시간을 크게 단축할 수 있다.
질의 다시 쓰기는 사용자가 명시한 명령 없이도 질의 최적화기에 의해 수행되므로 실체화 뷰를 인덱스처럼 사용할 수 있다. INSERT, DELETE, UPDATE, MERGE의 대상이 되는 부질의를 제외한 모든 SELECT 문에 동작한다.
EXPLAIN PLAN 문을 통해서 실행 계획을 보면 질의 다시 쓰기에 의해 참조된 실체화 뷰는 MV_REWRITE라고 표시된다.
질의 다시 쓰기 기능을 동작하기 위한 조건은 다음과 같다.
실체화 뷰를 생성할 때 ENABLE QUERY REWRITE 옵션을 추가해야 한다.
QUERY_REWRITE_ENABLED 파라미터의 값이 TRUE나 FORCE로 설정되어 있어야 한다.
QUERY_REWRITE_ENABLED = {TRUE | FORCE}
질의 다시 쓰기가 QUERY_REWRITE_INTEGRITY 파라미터의 설정을 만족시켜야 한다.
QUERY_REWRITE_INTEGRITY = {ENFORCED | STALE_TOLERATED}
QUERY_REWRITE_INTEGRITY 파라미터는 다음의 설정 값을 통해 질의 다시 쓰기의 정확도를 조절할 수 있다.
설정 값 | 설명 |
---|---|
ENFORCED | 최신 데이터가 있는 실체화 뷰만 사용하여 원본 질의와 동일한 결과를 보장한다. |
STALE_TOLERATED | 최신 데이터의 변경 내용이 반영되지 않은 실체화 뷰를 사용하기 때문에 원본 질의와 동일한 결과를 보장하지 않는다. 단, 질의 다시 쓰기가 될 가능성은 커진다. |
질의 다시 쓰기를 하려면 원본 질의와 사용할 실체화 뷰의 질의를 비교해서 원본 질의가 실체화 뷰를 사용해서 얻어질 수 있는지를 확인해야 한다. 현재는 완전 문자열 비교와 부분 문자열 비교 방식을 지원한다.
원본 질의와 사용할 실체화 뷰의 질의에 대해 전체 문자열을 비교한다. 이때 공백이나 대소문자의 차이는 무시된다.
예를 들어 다음과 같은 실체화 뷰가 있다고 가정해 보자.
CREATE MATERIALIZED VIEW MV_SUM_SALARY ENABLE QUERY REWRITE AS SELECT DNAME, SUM(SALARY) FROM DEPT, EMP WHERE DEPT.DEPTNO = EMP.DEPTNO GROUP BY DNAME;
다음과 같은 질의를 실행한다면,
SELECT dname, SUM(salary) FROM dept,emp WHERE DEPT.DEPTNO = EMP.DEPTNO GROUP BY dname;
다음과 같이 질의 다시 쓰기가 동작하게 된다.
SELECT * FROM MV_SUM_SALARY;
원본 질의와 사용할 실체화 뷰의 질의에 대해 FROM 절부터 ORDER BY 절 앞까지(존재할 경우)의 문자열을 비교하고, SELECT 리스트와 ORDER BY 절의 연산식에서 사용되는 컬럼의 적합성을 조사한다.
원본 질의의 SELECT 리스트 컬럼이 실체화 뷰의 컬럼을 조합해서 얻어질 수 있는지를 검사한다. 이때 조인에 의해 같아지는 컬럼을 처리한다.
예를 들어 다음과 같은 실체화 뷰가 있다고 가정해 보자.
CREATE MATERIALIZED VIEW MV_JOIN_DEPT_EMP ENABLE QUERY REWRITE AS SELECT ENAME, DNAME, DEPT.DEPTNO FROM DEPT, EMP WHERE DEPT.DEPTNO = EMP.DEPTNO;
다음과 같은 질의를 실행한다면,
SELECT ENAME, DNAME, EMP.DEPTNO FROM DEPT, EMP WHERE DEPT.DEPTNO = EMP.DEPTNO;
다음과 같이 질의 다시 쓰기가 동작하게 된다.
SELECT ENAME, DNAME, DEPTNO FROM MV_JOIN_DEPT_EMP;
또한, 연산의 교환, 결합, 분배 법칙을 이용하여 동등한 연산식의 컬럼을 처리한다.
예를 들어 다음과 같은 실체화 뷰가 있다고 가정해 보자.
CREATE MATERIALIZED VIEW mymv ENABLE QUERY REWRITE AS SELECT a*(c+4)+b c1, sum(c+a)+1 c2 FROM base GROUP BY a*(c+4)+b, b+4*a+a*c;
다음과 같은 질의를 실행한다면,
SELECT b+4*a+a*c+(1+sum(a+c))*7 FROM base GROUP BY a*(c+4)+b, b+4*a+a*c;
다음과 같이 질의 다시 쓰기가 동작하게 된다.
SELECT c1+c2*7 FROM mymv;
집단 함수를 사용할 때 집단 함수의 적합성을 조사하는 방법은 다음과 같다.
해당되는 집단 함수가 없어도 다른 집단 함수를 조합하여 원하는 집단 함수를 얻을 수 있다. 예를 들어 AVG(SALARY)는 SUM(SALARY) / COUNT(SALARY)로 구할 수 있다.
다음은 집단 함수의 적합성을 조사한 표이다.
목표 집단 함수 | 필요 집단 함수 |
---|---|
AVG(expr) | SUM(expr), COUNT(expr) |
SUM(expr) | AVG(expr), COUNT(expr) |
STDDEV(expr) | VARIANCE(expr) |
(STDDEV_SAMP(expr), STDDEV_POP(expr), VAR_SAMP(expr), VAR_POP(expr)) 중 하나, COUNT(expr) | |
SUM(expr * expr), SUM(expr), COUNT(expr) | |
STDDEV_SAMP(expr) | VAR_SAMP(expr) |
(STDDEV(expr), STDDEV_POP(expr), VARIANCE(expr), VAR_POP(expr)) 중 하나, COUNT(expr) | |
SUM(expr * expr), SUM(expr), COUNT(expr) | |
STDDEV_POP(expr) | VAR_POP(expr) |
(STDDEV(expr), STDDEV_SAMP(expr), VARIANCE(expr), VAR_SAMP(expr)) 중 하나, COUNT(expr) | |
SUM(expr * expr), SUM(expr), COUNT(expr) | |
VARIANCE(expr) | STDDEV(expr) |
(STDDEV_SAMP(expr), STDDEV_POP(expr), VAR_SAMP(expr), VAR_POP(expr)) 중 하나, COUNT(expr) | |
SUM(expr * expr), SUM(expr), COUNT(expr) | |
VAR_SAMP(expr) | STDDEV_SAMP(expr) |
(STDDEV(expr), STDDEV_POP(expr), VARIANCE(expr), VAR_POP(expr)) 중 하나, COUNT(expr) | |
SUM(expr * expr), SUM(expr), COUNT(expr) | |
VAR_POP(expr) | STDDEV_POP(expr) |
(STDDEV(expr), STDDEV_SAMP(expr), VARIANCE(expr), VAR_SAMP(expr)) 중 하나, COUNT(expr) | |
SUM(expr * expr), SUM(expr), COUNT(expr) |