Эта разновидность materialized view может создаваться только на основе таблицы, находящейся в той же схеме. Кроме этого, для ее создания нужно иметь особую привилегию QUERY REWRITE.
Подготовка примера
Выдадим от имени SYS:
GRANT QUERY REWRITE TO scott;
Построение примера
Выдадим в SQL*Plus от имени SCOTT:
CREATE MATERIALIZED VIEW dept_salaries ENABLE QUERY REWRITE AS SELECT dname, COUNT(emp.deptno) emp_count, SUM(sal) tot_sal FROM emp, dept WHERE emp.deptno (+) = dept.deptno GROUP BY dname;
(В следующем примере и в двух далее одинаковым фоном выделены одинаковые участки кода).
Выводимая таблица DEPT_SALARIES показывает список отделов, число работающих в них и фонд зарплаты. Число отделов:
SELECT COUNT(*) FROM dept_salaries;
Проверка работы переформулировки
Проанализируем таблицы (желательно) и сравним планы:
ANALYZE TABLE emp COMPUTE STATISTICS; ANALYZE TABLE dept COMPUTE STATISTICS; ANALYZE TABLE dept_salaries COMPUTE STATISTICS;
SET AUTOTRACE TRACEONLY EXPLAIN
SELECT dname, COUNT(emp.deptno) emp_count, SUM(sal) tot_sal FROM emp, dept WHERE emp.deptno (+) = dept.deptno GROUP BY dname;
ALTER SESSION SET QUERY_REWRITE_ENABLED=TRUE;
SELECT dname, COUNT(emp.deptno) emp_count, SUM(sal) tot_sal FROM emp, dept WHERE emp.deptno (+) = dept.deptno GROUP BY dname;
Два последних оператора SELECT идентичны.
Пример показывает, что мы можем продолжать работать с исходными таблицами независимо от того, построена выводимая таблица DEPT_SALARIES, или нет. СУБД сама определила, что таковая имеется, и переадресовала запрос к ней. Сама таблица DEPT_SALARIES не несет в себе новых данных и ее наличие, подобно наличию индекса, позволяет в некоторых случаях сократить время доступа к исходной информации.
Следующие примеры свидетельствуют, что для подобной автоматической переадресации к данным в приложении не обязательно повторять в точности формулировку имеющейся выводимой таблицы. Достаточно, чтобы в выводимой таблице с хранимым результатом хватало данных для ответа:
SELECT dname, COUNT(emp.deptno) emp_count FROM emp, dept WHERE emp.deptno (+) = dept.deptno GROUP BY dname;
SELECT dname, COUNT(emp.deptno) emp_count, SUM(sal) tot_sal FROM emp, dept WHERE emp.deptno (+) = dept.deptno AND dept.deptno <> 10 GROUP BY dname;