物化视图简介

这里小鱼也主要是学习下物化视图的特性,这里主要简单说下增量刷新和增量刷新失效的问题,关于物化视图网络的文章还是比较多的,特别是“杨长老”对物化视图有一系列文章,如果要深入的了解物化视图的还是可以去看看这些文章,相信一定会受益颇多。

着手测试下物化视图的特性:
SQL> create table xiaoyu01 as select object_id,object_name,object_type from dba_objects ;
SQL> create materialized view xiaoyu01_mv
2 refresh force
3 on demand
4 start with sysdate
5 next sysdate+1/1440
6 as
7 select object_id,object_name,object_type from xiaoyu01;

SQL> select mview_name,refresh_mode,refresh_method,last_refresh_date,staleness from user_mviews;

MVIEW_NAME REFRES REFRESH_ LAST_REFRESH_DATE STALENESS
-------------------- ------ -------- ------------------- -------------------
XIAOYU01_MV DEMAND FORCE 2013-08-08 17:16:44 FRESH

上面创建的物化视图刷新方法是手动force模式刷新。

关于物化视图刷新刷新时间可以分为on demand(需要时刷新)和on commit(dml提交前就刷新),而根据刷新的方法又可分为fast(增量刷新)、force(如果能增量刷新就增量刷新,反之则完全刷新)、complete(完全刷新)、NEVER(从不刷新)。

选择哪种刷新方式:
如果我们不考虑数据即时性选择on demand在需要时刷新,on commit模式刷新还是会一定程度影响dml效率的,而且commit刷新有一定的限制,同样刷新方式则是建议优先使用fast增量刷新,而增量刷新同样需要在基表建立基于rowid或者primary key的物化视图日志,同样增量刷新也有诸多的限制。
下面我们来看一个关于on commit即时刷新的限制:
数据库ora10g中建立基表和物化视图的日志
SQL> create table xiaoyu01 as select object_id,object_name,object_type from dba_objects where rownum<10;
SQL> alter table xiaoyu01 add primary key(object_id);
SQL> create materialized view log on xiaoyu01;(默认是创建基于主键的物化视图日志)

然后在远程的ora11g数据库中建立物化视图,并选择即时增量刷新
SQL> create materialized view xiaoyu01_mv
2 refresh fast with rowid
3 on commit
4 as
5 select object_id,object_name,object_type from xiaoyu01@ora10g;
select object_id,object_name,object_type from xiaoyu01@ora10g
*
ERROR at line 5:
ORA-12054: 无法为实体化视图设置 ON COMMIT 刷新属性

此时出现了上述的ora-12054的错误,而这个错误oracle的解释确是很模糊,并没有实际的信息
[oracle@ora11g ~]$ oerr ora 12054
12054, 00000, "cannot set the ON COMMIT refresh attribute for the materialized view"
// *Cause: The materialized view did not satisfy conditions for refresh at
// commit time.
// *Action: Specify only valid options.

这是因为on commit的物化视图不能包含远程dblink的对象,这个是个硬性的标准。

而增量刷新的限制也是比较多的,下面我们来重点来测试几个可能会碰到的:

所有类型的快速刷新物化视图都必须满足:
1不能包含对不重复表达式的引用、例如sysdate和rownum;
2物化视图不能包含LONG和LONG RAW数据类型的引用。
SQL> create materialized view test01_mv
2 refresh fast
3 as
4 select object_id,object_name,object_type,rownum cn from xiaoyu01;
select object_id,object_name,object_type,rownum cn from xiaoyu01
*
ERROR at line 4:
ORA-12015: cannot create a fast refresh materialized view from a complex query

SQL> create materialized view test01_mv
2 refresh fast
3 as
4 select object_id,object_name,object_type,sysdate cn from xiaoyu01;
select object_id,object_name,object_type,sysdate cn from xiaoyu01
*
ERROR at line 4:
ORA-12015: cannot create a fast refresh materialized view from a complex query

SQL> !oerr ora 12015
12015, 00000, "cannot create a fast refresh materialized view from a complex query"
// *Cause: Neither ROWIDs and nor primary key constraints are supported for
// complex queries.
// *Action: Reissue the command with the REFRESH FORCE or REFRESH COMPLETE
// option or create a simple materialized view.
上面看出o对其的解释是无论是rowid还是primary key物化视图日志都不支持包含sysdate和rownum形式的物化视图。

下面来测试下LONG数据类型
SQL> create table xiaoyu02(id number,name LONG,primary key(id));
SQL> create materialized view log on xiaoyu02;
SQL> create materialized view xiaoyu02_mv
2 refresh fast
3 as
4 select id,name from xiaoyu02;
select id,name from xiaoyu02
*
ERROR at line 4:
ORA-00997: illegal use of LONG datatype

同样对于LONG类型的数据物化视图也是不支持的。

2 只包含连接的物化视图:(这些限制摘要老杨的blog,老杨是在9I环境下测试的,这些限制条件可能随着oracle的版本而改变)
1.必须满足所有快速刷新物化视图都满足的条件;(不能拥有sysdate、rownum、LONG等数据类型)
2.不能包括GROUP BY语句或聚集操作;
3.如果在WHERE语句中包含外连接,那么唯一约束必须存在于连接中内表的连接列上;
4.如果不包含外连接,那么WHERE语句没有限制,如果包含外连接,那么WHERE语句中只能使用AND连接,并且只能使用“=”操作。
5.FROM语句列表中所有表的ROWID必须出现在SELECT语句的列表中。
6.FROM语句列表中的所有表必须建立基于ROWID类型的物化视图日志。

下面我们先来测试下包含聚集运算是否能用于连接的物化视图:
SQL> create table xiaoyu01(object_id number primary key,object_name varchar2(100));
SQL> insert into xiaoyu01 select object_id,object_name from dba_objects where rownum<3;
SQL> commit;
SQL> create materialized view log on xiaoyu01 with rowid;

SQL> create table xiaoyu02(data_object_id number primary key,object_type varchar2(100));
SQL> insert into xiaoyu02 select data_object_id,object_type from dba_objects where rownum<10;
SQL> commit;
SQL> create materialized view log on xiaoyu02 with rowid;

先创建一个连接的物化视图xiaoyu_join_mv01
SQL> create materialized view xiaoyu_join_mv01
2 refresh fast
3 as
4 select a.object_id,a.rowid rowid1,b.object_type,b.rowid rowid2 from xiaoyu01 a,xiaoyu02 b;

Materialized view created.
此时这个物化视图满足了没有聚合函数、select查询了所有基表的rowid信息,且基表都是基于rowid形式的物化视图日志。
SQL> drop materialized view xiaoyu_join_mv01;

测试聚集函数:
SQL> create materialized view xiaoyu_join_mv01
2 refresh fast
3 as
4 select a.object_id,a.rowid rowid1,b.object_type,b.rowid rowid2 from xiaoyu01 a,xiaoyu02 b
5 where a.object_id=b.data_object_id
6 group by a.object_id,a.rowid,b.object_type,b.rowid;
select a.object_id,a.rowid rowid1,b.object_type,b.rowid rowid2 from xiaoyu01 a,xiaoyu02 b
*
ERROR at line 4:
ORA-32401: materialized view log on "XIAOYU"."XIAOYU02" does not have new
Values
看出此时连接的增量物化视图是不支持聚合函数的

测试是否需要所有表的rowid信息:
下面我们去掉一个基表的rowid信息
SQL> create materialized view xiaoyu_join_mv01
2 refresh fast
3 as
4 select a.object_id,a.rowid rowid1,b.object_type from xiaoyu01 a,xiaoyu02 b;
select a.object_id,a.rowid rowid1,b.object_type from xiaoyu01 a,xiaoyu02 b
*
ERROR at line 4:
ORA-12052: cannot fast refresh materialized view XIAOYU.XIAOYU_JOIN_MV01
看出连接的增量物化视图必须select子句包含所有的rowid信息

测试是否需要所有表都需要建立rowid的物化视图日志:
下面我们删除xiaoyu01的rowid的物化视图日志,创建一个primary key的物化视图日志
SQL> drop materialized view log on xiaoyu01;
SQL> create materialized view log on xiaoyu01 with primary key;
SQL> create materialized view xiaoyu_join_mv01
2 refresh fast
3 as
4 select a.object_id,a.rowid rowid1,b.object_type,b.rowid rowid2 from xiaoyu01 a,xiaoyu02 b;
select a.object_id,a.rowid rowid1,b.object_type,b.rowid rowid2 from xiaoyu01 a,xiaoyu02 b
*
ERROR at line 4:
ORA-12032: cannot use rowid column from materialized view log on
"XIAOYU"."XIAOYU01"
此时无法创建物化视图,是因为xiaoyu01表的没有创建基于rowid的物化视图日志。

测试where条件的外连接:
SQL> create materialized view xiaoyu_join_mv02
2 refresh fast
3 as
4 select a.object_id,a.rowid rowid1,b.object_type,b.rowid rowid2 from xiaoyu01 a,xiaoyu02 b where a.object_id=b.data_object_id(+);

Materialized view created.

删除内表的主键约束,然后创建fast的物化视图(这里需要说明,小鱼在10g环境下测试发现外连接已经不存在上述的连接列必须是内表的唯一约束列,换句话说即使连接条件不是唯一约束列也是可以创建fast物化视图)
SQL> alter table xiaoyu01 drop primary key;
SQL> drop materialized view xiaoyu_join_mv02;
SQL> create materialized view xiaoyu_join_mv02
2 refresh fast
3 as
4 select a.object_id,a.rowid rowid1,b.object_type,b.rowid rowid2 from xiaoyu01 a,xiaoyu02 b where a.object_id=b.data_object_id(+);

Materialized view created.

Where外连接中是否支持or和非=运算:
SQL> create materialized view xiaoyu_join_mv02
2 refresh fast
3 as
4 select a.object_id,a.rowid rowid1,b.object_type,b.rowid rowid2 from xiaoyu01 a,xiaoyu02 b where a.object_id=b.data_object_id(+)
5 or b.object_type!='TABLE';
select a.object_id,a.rowid rowid1,b.object_type,b.rowid rowid2 from xiaoyu01 a,xiaoyu02 b where a.object_id=b.data_object_id(+)
*
ERROR at line 4:
ORA-01719: outer join operator (+) not allowed in operand of OR or IN

SQL> create materialized view xiaoyu_join_mv02
2 refresh fast
3 as
4 select a.object_id,a.rowid rowid1,b.object_type,b.rowid rowid2 from xiaoyu01 a,xiaoyu02 b where a.object_id=b.data_object_id(+) and b.object_type!=a.object_name;

Materialized view created.
看出此时即使外连接情况下也是支持非=运算的,但是却不支持or查询的fast物化视图

包含聚集的物化视图限制:
1.必须满足所有快速刷新物化视图都满足的条件;
2.物化视图查询的所有表必须建立物化视图日志,且物化视图日志必须满足下列限制:
(1)包含物化视图查询语句中的所有列,包括SELECT列表中的列和WHERE语句中的列;
(2)必须指明ROWID和INCLUDING NEW VALUES;
(3)如果对基表的操作同时包括INSERT、UPDATE和DELETE操作(即不是只包含INSERT操作),那么物化视图日志应该包括SEQUENCE。
3.允许的聚集函数包括:SUM、COUNT、AVG、STDDEV、VARIANCE、MIN和MAX;
4.必须指定COUNT(*);
不加COUNT(*),建立快速刷新的物化视图会成功,但通过执行EXPLAIN_MVIEW过程,可以发现, COUNT(*)对于INSERT操作是可以快速刷新的,不过对于UPDATE和DELETE则会造成快速刷新的失败。
5.如果指明了除COUNT之外的聚集函数,则COUNT(expr)也必须存在;
比如:包含SUM(a),则必须同时包含COUNT(a)。
6.如果指明了VARIANCE(expr)或STDDEV(expr),除了COUNT(expr)外,SUM(expr)也必须指明;
Oracle推荐同时包括SUM(expr*expr)。
7.SELECT列表中必须包括所有的GROUP BY列;
8.当物化视图属于下面的某种情况,则快速刷新只支持常规DML插入和直接装载,这种类型的物化视图又称为INSERT-ONLY物化视图;
物化视图包含MIN或MAX聚集函数;
物化视图包含SUM(expr),但是没有包括COUNT(expr);
物化视图没有包含COUNT(*)。
注意:如果建立了这种物化视图且刷新机制是ON COMMIT的,则会存在潜在的问题。当出现了UPDATE或DELETE语句,除非手工完全刷新解决这个问题,否则物化视图至此以后都不再自动刷新,且不会报任何错误。
9.如果包含inline views、outer joins、self joins或grouping set,则兼容性的设置必须在9.0以上;
10.如果物化视图建立在视图或子查询上,则要求视图必须可以完全合并的。
11.如果没有外连接,则对WHERE语句没有限制。如果包含外连接,则要求WHERE语句只能包括AND连接和“=”操作。对于包含外连接的聚集物化视图,快速刷新支持outer表的修改。且inter表的连接列上必须存在唯一约束。
12.对于包含了ROLLUP、CUBE、GROUPING SET的物化视图必须满足下列限制条件:
SELECT语句列表中应该包含GROUPING标识符:可以是GROUP BY表达式中所有列的GROUPING_ID函数,也可以是GROUP BY表达式中每一列的GROUPING函数;
例如:GROUP BY语句为:GROUP BY CUBE(a, b),则SELECT列表应该包括GROUPING_ID(a, b)或者GROUPING(a)和GROUPING(b)。
GROUP BY不能产生重复的GROUPING。
比如:GROUP BY a,ROLLUP(a, b)则不支持快速刷新,因为包含了重复的GROUPING:(a), (a, b), (a)。

这里小鱼只演示如何创建一个fast聚合类型的物化视图:
首先需要创建一个基于rowid的物化视图日志
SQL> create materialized view log on xiaoyu01 with rowid ,sequence(object_id,object_name) including new values;

Materialized view log created.
这里如果要支持fast刷新必须设置rowid including new values特性,而如果要支持update和delete操作则还需要设置sequence属性记录操作的顺序。
SQL> create materialized view xiaoyu_jh_mv01
2 refresh fast
3 as
4 select object_id,object_name from xiaoyu01 group by object_id,object_name;

Materialized view created.

包含UNION ALL的物化视图
1.UNION ALL操作必须在查询的顶层。可以有一种情况例外:UNION ALL在第二层,而第一层的查询语句为SELECT * FROM;
2.被UNION ALL操作连接在一起的每个查询块都应该满足快速刷新的限制条件;
3.SELECT列表中必须包含一列维护列,叫做UNION ALL标识符,每个UNION ALL分支的标识符列应包含不同的常量值;
4.不支持外连接、远端数据库表和包括只允许插入的聚集物化视图定义查询;
5.不支持基于分区改变跟踪(PCT)的刷新;
6.兼容性设置应设置为9.2.0。

嵌套物化视图
嵌套物化视图的每层都必须满足快速刷新的限制条件;
对于同时包含聚集和连接的嵌套物化视图,不支持ON COMMIT的快速刷新。

由于增量刷新的物化视图的限制较多,这里不方便全部列出测试,而且有些小鱼也没有去测试,下面摘要老杨的一些关于聚集、union all和嵌套增量刷新的总结,如果有时间可以自己去测试下,这里小鱼就只测试上面的分类1和分类2了。

而oracle提供给我们一个如何去查看物化视图无法创建的一种方法:
Oracle内置的存储过程配合基表来查看具体物化视图无法创建的原因
[oracle@ora11g admin]$ cd $ORACLE_HOME/rdbms/admin
[oracle@ora11g admin]$ sqlplus / as sysdba
SQL> start utlxmv.sql
执行这个脚本会创建mv_capabilities_table这个表,这个表用于存储无法创建物化视图的具体信息。

然后执行存储过程,将分析后面无法创建物化视图的原因。(sql语句是创建物化视图对应的select sql语句)
SQL> execute dbms_mview.explain_mview('select object_id,object_name,object_type from xiaoyu01@ora10g');

PL/SQL procedure successfully completed.

大家如果维护过物化视图还可能会碰到增量刷新失效的问题,如果对物化视图的基表做过某些ddl、或者删除过物化视图日志的信息则就可能造成增量刷新失效,比如删除物化视图日志或者对基表增删列、truncate等操作:
1 模拟基表truncate操作:
SQL> create materialized view xiaoyu_ddl_mv01
2 refresh fast with rowid
3 as
4 select object_id,object_name from xiaoyu01;

Materialized view created.

SQL> truncate table xiaoyu01;

Table truncated.

SQL> execute dbms_mview.refresh('XIAOYU_DDL_MV01');
BEGIN dbms_mview.refresh('XIAOYU_DDL_MV01'); END;

*
ERROR at line 1:
ORA-12034: materialized view log on "XIAOYU"."XIAOYU01" younger than last
refresh
ORA-06512: at "SYS.DBMS_SNAPSHOT", line 2251
ORA-06512: at "SYS.DBMS_SNAPSHOT", line 2457
ORA-06512: at "SYS.DBMS_SNAPSHOT", line 2426
ORA-06512: at line 1

这种情况下只能全量刷新或重建物化视图来解决。
SQL> execute dbms_mview.refresh('XIAOYU_DDL_MV01','C');

2 模拟对物化视图日志ddl
SQL> insert into xiaoyu01 values(9999,'OBJ');
SQL> commit;
SQL> truncate table mlog$_xiaoyu01;

上面对物化视图日志进行truncate后,手动fast刷新物化视图则又出现了ora-12034的错误
SQL> execute dbms_mview.refresh('XIAOYU_DDL_MV01');
BEGIN dbms_mview.refresh('XIAOYU_DDL_MV01'); END;

ERROR at line 1:
ORA-12034: materialized view log on "XIAOYU"."XIAOYU01" younger than last
refresh
ORA-06512: at "SYS.DBMS_SNAPSHOT", line 2251
ORA-06512: at "SYS.DBMS_SNAPSHOT", line 2457
ORA-06512: at "SYS.DBMS_SNAPSHOT", line 2426
ORA-06512: at line 1

而如果对物化视图日志进行的是delete操作则刷新不会出现问题,但是基表和物化视图的数据会出现不一致
SQL> insert into xiaoyu01 values(99999,'PO');
SQL> commit;
SQL> delete from mlog$_xiaoyu01;
SQL> commit;
SQL> execute dbms_mview.refresh('XIAOYU_DDL_MV01');
SQL> select count(*) from xiaoyu01 union all
2 select count(*) from xiaoyu_ddl_mv01;

COUNT(*)
----------
2
1

你可能感兴趣的:(物化视图)