文字部分基本上都是官方文档翻译过来的,不准确的地方请谅解。
物化视图可用于查询重写,即使它们并不完全与基表同步,并且被认为失效。 使用物化视图日志与增量计算以及陈旧的物化视图,数据库可以计算查询并实时返回正确的结果。
对于可以用于所有时间的查询重写的物化视图,通过实时计算准确的结果,结果得到优化,并且快速查询处理以获得最佳性能。 这减轻了总是必须具有新的物化视图以获得最佳性能的严格要求。
1 使用实时物化视图
实时物化视图即使在物化视图数据被标记为过旧时也向用户查询提供新数据。
1.1 实时物化视图的概述
实时物化视图是视图的一种,它可以向用户提供新数据,即使由于数据改变造成物化视图是不同步的。
除非将SQL会话设置为过时容错模式,否则标记为陈旧的实例化视图不能用于查询重写。 需要实时数据的组织通常使用ON COMMIT刷新模式,以确保使用对基表所做的更改来更新物化视图。 但是,当DML更改为基本表非常大且非常频繁时,此模式可能导致资源争用并降低刷新性能。 实时物化视图提供了一个轻量级的解决方案,可以通过重新计算数据来获取陈旧的物化视图中的新数据。
实时物化视图可以使用任何可用的异地刷新方法,包括基于日志或基于PCT的刷新。 它们可以根据需要或计划的自动刷新使用,但不能与使用ON COMMIT子句指定的自动刷新一起使用。
实时物化视图的好处:
- 为实体化视图提供改进的可用性
- 为访问可能陈旧的实例化视图的用户查询提供新数据
实时物化视图是如何工作的?
实时物化视图使用一种称为查询计算的技术来提供具有陈旧物化视图的新数据。当查询访问实时物化视图时,Oracle数据库首先检查实时物化视图是否标记为失效。如果它不是陈旧的,则使用实时物化视图来提供所需的数据。如果实时物化视图被标记为陈旧,则使用查询计算技术来生成新数据并返回正确的查询结果。
实时物化视图使用类似基于日志的刷新技术,以提供具有陈旧物化视图的新数据。它们将现有数据与更改日志中记录的更改组合,以获取最新数据。然而,与基于日志的刷新不同,实时物化视图不使用实体化视图日志来更新实时物化视图中的数据。相反,当查询访问陈旧的实时物化视图时,使用查询计算重新计算的数据直接用于回答查询。
通过在物化视图定义中使用ON QUERY COMPUTATION子句创建实时物化视图。
1.1.1 使用实时物化视图的限制
实时物化视图不能用于以下情况:
- 在基本表上创建的一个或多个物化视图日志不可用或不存在。
- 异地,基于日志或PCT刷新对于变化情形是不可行的。
- 则使用ON COMMIT子句指定自动刷新。
- 如果实时物化视图是在一个或多个基本物化视图之上定义的嵌套物化视图,则仅当所有基本物化视图都是新的时才进行查询重写。 如果一个或多个基本物化视图是陈旧的,则不使用该实时物化视图来执行查询重写。
直接访问实时物化视图的查询的游标不会共享。
1.1.2 关于访问实时物化视图
与物化视图一样,存在多种方法来访问存储在实时物化视图中的数据。
存储在实时物化视图中的数据可以通过以下方式之一访问:
- 查询重写
类似于实时物化视图定义的用户查询被重写以使用实时物化视图。 - 直接访问实时物化视图
用户查询通过使用其名称直接引用实时物化视图。
在这两种情况下,实时物化视图的内容可以作为陈旧数据访问,或者可以触发正确结果的查询计算。 是否触发查询计算取决于环境和实际的SQL语句。
EXPLAIN PLAN语句的输出包含指示查询计算是否用于特定用户查询的消息。
1.2 创建实时物化视图
实时物化视图必须使用非本地的基于日志的刷新机制(包括PCT刷新)。 ON COMMIT刷新模式不能用于实时物化视图。
为了创建一个实时物化视图:
- 确保物化视图日志存在于实时物化视图的所有基表上。
- 为实时物化视图所基于的所有表创建物化视图日志。
- 通过在CREATE MATERIALIZED VIEW语句中包含ENABLE ON QUERY COMPUTATION子句来创建实时物化视图。
1.2.1 在基本表DEPT和EMP上创建物化视图日志。
以下命令在SALES和PRODUCTS表上创建物化视图日志:
SQL> CREATE MATERIALIZED VIEW LOG ON dept
WITH SEQUENCE, ROWID
(deptno, dname, loc)
INCLUDING NEW VALUES; 2 3 4
Materialized view log created.
SQL> CREATE MATERIALIZED VIEW LOG ON emp
WITH ROWID
(empno, ename, job,sal,deptno)
INCLUDING NEW VALUES; 2 3 4
Materialized view log created.;
1.2.2 创建物化视图
通过在CREATE MATERIALIZED VIEW语句中包含ON QUERY COMPUTATION子句来创建实时物化视图。 快速刷 新方法用于此实时物化视图,ENABLE QUERY REWRITE子句指示必须启用查询重写。
SQL> CREATE MATERIALIZED VIEW emp_dept_mv
REFRESH FAST ON DEMAND
ENABLE QUERY REWRITE
ENABLE ON QUERY COMPUTATION
AS
SELECT count(*),dname,sum(sal)
FROM dept, emp
WHERE dept.deptno = emp.deptno
GROUP BY dname; 2 3 4 5 6 7 8 9
Materialized view created.
1.2.3 创建完实时物化视图,执行下面的查询
如果emp_dept_mv不是过时的,则使用存储在该实时物化视图中的数据返回查询结果。 但是,如果emp_dept_mv过时,并且使用具有查询计算的物化视图重写查询的成本低于基表访问时,则通过组合DEPT和EMP上的物化视图日志中的增量变化来回答查询 表与实时物化视图emp_dept_mv中的数据。
SQL> alter session set STATISTICS_LEVEL = ALL;
Session altered.
SQL> SELECT count(*),dname,sum(sal)
FROM dept, emp
WHERE dept.deptno = emp.deptno
GROUP BY dname; 2 3 4
COUNT(*) DNAME SUM(SAL)
---------- ---------------------------- ----------
3 ACCOUNTING 8750
3 RESEARCH 6775
6 SALES 9400
SQL> select * from table(dbms_xplan.DISPLAY_CURSOR(null, null, 'ALLSTATS'));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID fjxbvv21151zg, child number 0
------------------------------------------------------------------------------------------------------------------------
SELECT count(*),dname,sum(sal) FROM dept, emp WHERE dept.deptno =
emp.deptno GROUP BY dname
Plan hash value: 3212952337
---------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 3 |00:00:00.01 | 10 |
| 1 | MAT_VIEW REWRITE ACCESS FULL| EMP_DEPT_MV | 1 | 3 | 3 |00:00:00.01 | 10 |
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
14 rows selected.
通过执行计划,可以看到执行该SQL,是从刚刚创建的物化视图中取数据的。
1.2.3.1 下面修改一个表的数据,看看执行计划是怎么样变化的
插入点新数据,看看是否有变化。
SQL> SELECT count(*),dname,sum(sal)
FROM dept, emp
WHERE dept.deptno = emp.deptno
GROUP BY dname; 2 3 4
COUNT(*) DNAME SUM(SAL)
---------- ---------------------------- ----------
13 ACCOUNTING 18750
13 RESEARCH 16775
21 SALES 24500
SQL> select * from table(dbms_xplan.DISPLAY_CURSOR(null, null, 'ALLSTATS'));
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID fjxbvv21151zg, child number 1
-------------------------------------
SELECT count(*),dname,sum(sal) FROM dept, emp WHERE dept.deptno =
emp.deptno GROUP BY dname
Plan hash value: 2708255165
------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | O/1/M |
------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | | 12 |00:00:00.01 | 36 | | | |
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 1 | HASH GROUP BY | | 4 | 4 | 12 |00:00:00.01 | 36 | 1048K| 1048K| 4/0/0|
| 2 | MERGE JOIN | | 4 | 12 | 83 |00:00:00.01 | 36 | | | |
| 3 | TABLE ACCESS BY INDEX ROWID| DEPT | 4 | 4 | 16 |00:00:00.01 | 8 | | | |
| 4 | INDEX FULL SCAN | PK_DEPT | 4 | 4 | 16 |00:00:00.01 | 4 | | | |
|* 5 | SORT JOIN | | 16 | 12 | 83 |00:00:00.01 | 28 | 2048 | 2048 | 4/0/0|
| 6 | TABLE ACCESS FULL | EMP | 4 | 12 | 83 |00:00:00.01 | 28 | | | |
------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------
5 - access("DEPT"."DEPTNO"="EMP"."DEPTNO")
filter("DEPT"."DEPTNO"="EMP"."DEPTNO")
28 rows selected.
可以看到,没有通过物化视图取数据了,说明直接访问基表的成本比查询计算的物化视图重写查询的成本低。
1.3 将物化视图转换为实时物化视图
如果对于实时物化视图的前提条件满足,那么可以通过修改它的定义和启用ON-QUERY计算将其转换为实时物化视图。
如:
SQL> ALTER MATERIALIZED VIEW sales_rtmv ENABLE ON QUERY COMPUTATION;
相反,使用DISABLE ON QUERY COMPUTATION将实时物化视图转换为物化视图。
通过查看DBA_MVIEWS来确定SALES_RTMV视图的ON-QUERY计算是否启用了。
SQL> SELECT mview_name, on_query_computation
FROM dba_mviews
WHERE mview_name = 'SALES_RTMV';
1.4 启用查询重写为了使用实时物化视图
对于重写一个用户查询以使用实时物化视图的查询重写机制,必须为实时物化视图启用查询重写。
对于实时物化视图,可以在创建时或者创建后再修改其定义来启用查询重写。下面就是通过修改其定义来启用查询重写功能:
SQL> ALTER MATERIALIZED VIEW my_rtmv ENABLE QUERY REWRITE;
1.5 在查询重写期间使用实时物化视图
如果为实时物化视图启用了查询重写,则查询重写可以使用实时物化视图来向用户查询提供结果,即使实时物化视图是陈旧的。 嵌套实时物化视图只有在其所有基本实时物化视图都是新的时才有资格进行查询重写。
当运行用户查询时,查询重写首先检查是否有新的物化视图可用于提供所需的数据。 如果一个合适的物化视图不存在,那么查询重写寻找一个实时物化视图,可以用来重写用户查询。 相对于实时物化视图,新的物化视图是优选的,因为在计算用于实时物化视图的新数据时会产生一些开销。 接下来,基于成本的优化器使用查询计算确定SQL查询的成本,然后确定实时物化视图是否将用于回答此用户查询。
如果当前SQL会话的QUERY_REWRITE_INTEGRITY模式设置为STALE_TOLERATED,则在查询重写期间不会使用查询计算。 STALE_TOLERATED重写模式指示不需要新的结果来满足查询,因此不需要查询计算。
对于查询重写使用实时物化视图:
- 确保QUERY_REWRITE_INTEGRITY设置为ENFORCED或TRUSTED模式。 QUERY_REWRITE_INTEGRITY模式不应设置为STALE_TOLERATED模式
- 运行与用于定义实时物化视图的SQL查询匹配的用户查询。可以重写以利用实时物化视图的任何查询将使用具有查询计算的实时物化视图。
可以通过 EXPLAIN PLAN来证明,该查询被使用实时物化视图重写了。
1.6 直接访问实时物化视图
在查询中,可以通过物化视图名称,可以直接访问实时物化视图。
在这例子中,首先创建基于SALES_NEW表的实时物化视图MY_RTMV。 SALES_NEW表作为SH.SALES表的副本创建。 创建实时物化视图后,将在基表中插入一行。 接下来,通过在用户查询中使用实例化视图名称,使用fresh_mv提示来访问来自实时物化视图的新数据。
1.6.1 创建物化视图日志:
SQL> CREATE MATERIALIZED VIEW LOG ON dept
WITH SEQUENCE, ROWID
(deptno, dname, loc)
INCLUDING NEW VALUES; 2 3 4
Materialized view log created.
SQL> CREATE MATERIALIZED VIEW LOG ON emp
WITH ROWID
(empno, ename, job,sal,deptno)
INCLUDING NEW VALUES; 2 3 4
Materialized view log created.;
1.6.2 创建实时物化视图emp_dept_mv2
注意创建语句的参数部分
SQL> CREATE MATERIALIZED VIEW emp_dept_mv2
REFRESH FAST
ENABLE ON QUERY COMPUTATION
ENABLE QUERY REWRITE
AS
SELECT count(*),dname,sum(sal)
FROM dept, emp
WHERE dept.deptno = emp.deptno
GROUP BY dname;
Materialized view created.
1.6.3 查看现在视图数据
SQL> SELECT * from emp_dept_mv2;
COUNT(*) DNAME SUM(SAL)
---------- ---------------------------- ----------
13 ACCOUNTING 18750
13 RESEARCH 16775
22 SALES 25500
1.6.4 插入一条数据
SQL> insert into emp values(201,'a','','','',1000,'',30);
1 row created.
SQL> commit;
Commit complete.
1.6.5 再次查询物化视图
SQL> SELECT * from emp_dept_mv2;
COUNT(*) DNAME SUM(SAL)
---------- ---------------------------- ----------
13 ACCOUNTING 18750
13 RESEARCH 16775
22 SALES 25500
可以看到,查询结果没有显示此数据的更新值。 这是因为实时物化视图尚未使用对其基表所做的更改进行刷新。
- 在查询时,使用hint FRESH_MV
SQL> SELECT /*+ fresh_mv */ * FROM emp_dept_mv2;
COUNT(*) DNAME SUM(SAL)
--------------------------- ---------- ----------
ACCOUNTING 13 18750
RESEARCH 13 16775
SALES 23 26500
可以看到,此时将显示更新的行,SUM(SAL)增加了1000。 这是因为FRESH_MV提示触发实时物化视图的查询计算,并重新计算新数据。
1.7 查看所有实时物化视图
数据字典视图ALL_MVIEWS,DBA_MVIEWS和USER_MVIEWS中的ON_QUERY_COMPUTATION列指示物化视图是否为实时物化视图。
如:
SQL> SELECT owner, mview_name, rewrite_enabled, staleness
FROM user mviews
WHERE on_query_computation = 'Y'; 2 3
OWNER MVIEW_NAME REWRI STALENESS
---------- ------------------------------ ----- --------------------
OE EMP_DEPT_MV Y NEEDS_COMPILE
OE EMP_DEPT_MV2 Y STALE
1.8 提高实时物化视图性能
要为使用实时物化视图的用户查询获得更好的性能,可以参考下面的一些指南.
对实时物化视图使用以下准则:
- 频繁刷新实时物化视图,以提高可能使用这些实时物化视图的查询的性能。
由于实时物化视图通过将基表的增量变化与现有物化视图数据组合起来工作,所以当要计算的增量变化较小时,增强了查询响应时间。使用更出色的DML操作,查询计算可能变得更加复杂(并且昂贵),直到直接基表访问可以变得更有效(在查询重写的情况下)的程度。 - 收集基本表,实时物化视图和物化视图日志的统计信息,以使优化器能够准确确定查询的成本。
对于查询重写,基于成本的重写机制使用优化器来确定是否应使用重写的查询。优化器使用统计信息确定成本。
更多详细信息还是看官方文档:
http://docs.oracle.com/database/122/NEWFT/new_features.htm#GUID-328AC469-788E-495E-BAB8-B3F9C827F3BE