物化视图作为sql调优的一种手段广泛用在数据仓库环境下,在我们的网站中,前台的访问类似OLTP系统,因而只要考虑和解决并发的问题,尽量的保证共享池中的库缓存和数据库字典缓存的命中率,但后台的操作则类似于DSS系统,大量的长查询语句,处理的不好,就会引起严重的I/O问题,下面这个sql语句就在后台执行了4432秒后报ORA-01555快照太旧错误,因而想到用物化视图对个别语句进行优化下,据程序员描述,使用物化视图后,相同的语句基本在10秒内可以完成!
ORA-01555 caused by SQL statement below (SQL ID: 4rf1j4aw2mpkm, Query Duration=4432 sec, SCN: 0x0000.03cababb): select d.id,d.subject,d.signinid,d.membership from (select c.*,rownum rownum_ from (select a.id,a.subject,b.signinid,b.membership from b2b_a a,b2b_b b where a.company_id=b.id and a.status=1 and a.deletetag=0 and a.subject is not null and b.status=1 and regexp_like (b.signinid,'^[a-z0-9_-]+$') order by a.id) c where rownum<=1920390) d where rownum_>1920290 |
由此可见,物化视图的威力,所以不得不好好学习下物化视图!那么为什么物化视图具备如此好的性能呢?
参考:http://blog.csdn.net/XIAOHUI_LIAO/article/details/1759990,感谢作者分享!
物化视图可以用于预先计算并保存表连接或聚集等耗时较多的操作的结果,这样,在执行查询时,就可以避免进行这些耗时的操作,而从快速的得到结果;
物化视图有很多方面和索引很相似:使用物化视图的目的是为了提高查询性能;
物化视图对应用透明,增加和删除物化视图不会影响应用程序中SQL语句的正确性和有效性;
物化视图需要占用存储空间;当基表发生变化时,物化视图也应当刷新;
物化视图还支持通过数据库链来做数据复制;
创建方式(Build Methods):包括BUILD IMMEDIATE和BUILD DEFERRED两种。BUILD IMMEDIATE是在创建物化视图的时候就生成数据,而BUILD DEFERRED则在创建时不生成数据,以后根据需要在生成数据。默认为BUILD IMMEDIATE;
查询重写(Query Rewrite):包括ENABLE QUERY REWRITE和DISABLE QUERY REWRITE两种。分别指出创建的物化视图是否支持查询重写。查询重写是指当对物化视图的基表进行查询时,Oracle会自动判断能否通过查询物化视图来得到结果,如果可以,则避免了聚集或连接操作,而直接从已经计算好的物化视图中读取数据。默认为DISABLE QUERY REWRITE;
关于查询重写的演示可参考:http://space.itpub.net/519536/viewspace-697891
刷新(Refresh):指当基表发生了DML操作后,物化视图何时采用哪种方式和基表进行同步。刷新的模式有两种:ON DEMAND和ON COMMIT。ON DEMAND指物化视图在用户需要的时候进行刷新,可以手工通过DBMS_MVIEW.REFRESH等方法来进行刷新,也可以通过JOB定时进行刷新。ON COMMIT指出物化视图在对基表的DML操作提交的同时进行刷新。刷新的方法有四种:FAST、COMPLETE、FORCE和NEVER。FAST刷新采用增量刷新,只刷新自上次刷新以后进行的修改。COMPLETE刷新对整个物化视图进行完全的刷新。如果选择FORCE方式,则Oracle在刷新时会去判断是否可以进行快速刷新,如果可以则采用FAST方式,否则采用COMPLETE的方式。NEVER指物化视图不进行任何刷新。默认值是FORCE ON DEMAND;
在建立物化视图的时候可以指定ORDER BY语句,使生成的数据按照一定的顺序进行保存。不过这个语句不会写入物化视图的定义中,而且对以后的刷新也无效;
物化视图日志:如果需要进行快速刷新,则需要建立物化视图日志。物化视图日志根据不同物化视图的快速刷新的需要,可以建立为ROWID或PRIMARY KEY类型的。还可以选择是否包括SEQUENCE、INCLUDING NEW VALUES以及指定列的列表;
可以指明ON PREBUILD TABLE语句将物化视图建立在一个已经存在的表上。这种情况下,物化视图和表必须同名。当删除物化视图时,不会删除同名的表。这种物化视图的查询重写要求参数QUERY_REWRITE_INTEGERITY必须设置为trusted或者stale_tolerated;
物化视图可以进行分区。而且基于分区的物化视图可以支持分区变化跟踪(PCT)。具有这种特性的物化视图,当基表进行了分区维护操作后,仍然可以进行快速刷新操作。 对于聚集物化视图,可以在GROUP BY列表中使用CUBE或ROLLUP,来建立不同等级的聚集物化视图;
下面来演示下使用物化视图在数据库间对表进行复制
一:在源库上创建用户和基表
- SQL> create tablespace mv_tbs;
- Tablespace created.
- SQL> create user t1 identified by t1 account unlock default tablespace mv_tbs temporary
- tablespace temp;
- User created.
- SQL> grant connect,resource,create materialized view to t1;
- Grant succeeded.
- SQL> grant select_catalog_role to t1;
- Grant succeeded.
- SQL> conn t1/t1
- Connected.
- SQL> create table t1 as select * from dba_objects;
- Table created.
- SQL> alter table t1 add constraint pk_t1 primary key(object_id);
- Table altered.
- SQL> create table t2 as select * from dba_objects;
- Table created.
- SQL> alter table t2 add constraint pk_t2 primary key(object_id);
- Table altered.
- SQL> create materialized view log on t1 with primary key;
- Materialized view log created.
- SQL> create materialized view log on t2 with primary key;
- Materialized view log created.
二:在目标库上创建用户和物化视图
- C:\>sqlplus sys/[email protected]:1521/target as sysdba
- SQL> create user t2 identified by t2 default tablespace users account unlock;
- User created.
- SQL> grant connect,resource,create materialized view,create database link to t2;
- Grant succeeded.
- SQL> conn t2/[email protected]:1521/target
- Connected.
- SQL> create database link source_db connect to t1 identified by t1 using 'source';
- Database link created.
- SQL> select count(*) from t1@source_db;
- COUNT(*)
- ----------
- 50380
- SQL> select count(*) from t2@source_db;
- COUNT(*)
- ----------
- 50382
- SQL> col object_name for a20
- SQL> col owner for a20
- SQL> select c.object_name,c.owner,c.status,c.last_ddl_time from (select
- a.rowid,b.rowid,a.object_name,a.owner,b.status,b.last_ddl_time from t1@source_db
- a,t2@source_db b where a.object_id=b.object_id and a.owner <> 'SYS' order by
- a.last_ddl_time desc) c where rownum<=10;
- OBJECT_NAME OWNER STATUS LAST_DDL_TIME
- -------------------- -------------------- ------- -------------------
- T1 T1 VALID 2012-05-25:10:37:22
- RLM$EVTCLEANUP EXFSYS VALID 2012-05-25:10:30:52
- RLM$SCHDNEGACTION EXFSYS VALID 2012-05-25:10:29:34
- T2 ABC VALID 2012-05-09:11:37:11
- T1 HR VALID 2012-05-09:11:34:58
- FUNC_DROP_VPD TEST VALID 2012-02-17:13:19:58
- PROC_DROP2_SELECT_AU TEST VALID 2012-02-17:11:18:28
- DIT
- DROP_AUDIT TEST VALID 2012-02-17:11:15:12
- OGG_TEST OGG VALID 2012-02-10:14:41:56
- OBJECT_NAME OWNER STATUS LAST_DDL_TIME
- -------------------- -------------------- ------- -------------------
- SYS_C006742 OGG VALID 2012-02-10:14:33:49
- 10 rows selected.
- SQL> create materialized view mv_join_t build immediate refresh force start with
- sysdate next sysdate+2880 enable query rewrite
- as
- select c.object_name,c.owner,c.status,c.last_ddl_time from (select
- a.rowid,b.rowid,a.object_name,a.owner,b.status,b.last_ddl_time from t1@source_db
- a,t2@source_db b where a.object_id=b.object_id and a.owner <> 'SYS' order by
- a.last_ddl_time desc) c;
- Materialized view created.
- SQL> select owner,mview_name,rewrite_enabled,refresh_mode,refresh_method,last_re
- fresh_date from user_mviews;
- OWNER MVIEW_NAME REW REFRESH_MO REFRESH_ME LAST_REFRESH_DATE
- ---------- ---------- --- ---------- ---------- -------------------
- T2 MV_JOIN_T Y DEMAND FORCE 2012-05-29-09:29:46
- SQL> select sum(bytes/(1024*1024)) MB from user_segments where segment_name='MV
- _JOIN_T';
- MB
- ----------
- 2
- SQL> select max(object_id) from t1@source_db;
- MAX(OBJECT_ID)
- --------------
- 54895
- SQL> select count(*) from mv_join_t;
- COUNT(*)
- ----------
- 27470
- SQL> insert into t1@source_db (object_id) values (54896);
- 1 row created.
- SQL> update t1@source_db set object_name='TEST',owner='T2' where object_id=54896
- ;
- 1 row updated.
- SQL> commit;
- Commit complete.
- SQL> exec dbms_mview.refresh('MV_JOIN_T','C');
- PL/SQL procedure successfully completed.
- SQL> select owner,mview_name,rewrite_enabled,refresh_mode,refresh_method,last_re
- fresh_date from user_mviews;
- OWNER MVIEW_NAME REW REFRESH_MO REFRESH_ME LAST_REFRESH_DATE
- ---------- ---------- --- ---------- ---------- -------------------
- T2 MV_JOIN_T Y DEMAND FORCE 2012-05-29-09:45:45
- SQL> select count(*) from mv_join_t;
- COUNT(*)
- ----------
- 27471
三:源库上查看物化视图日志信息
- SQL> col M_ROW$$ for a30
- SQL> col name for a10
- SQL> col CHANGE_VECTOR$$ for a10
- SQL> select * from MLOG$_T1;
- OBJECT_ID SNAPTIME$$ D O CHANGE_VEC M_ROW$$
- ---------- ------------------- - - ---------- ------------------------------
- 54896 4000-01-01:00:00:00 I N FEFF AAANZvAAIAAAALhAAA
- 54896 4000-01-01:00:00:00 U U 0600 AAANZvAAIAAAALhAAA
SNAPTIME$$:用于表示刷新时间
DMLTYPE$$:用于表示DML操作类型,I表示INSERT,D表示DELETE,U表示UPDATE
OLD_NEW$$:用于表示这个值是新值还是旧值。N(EW)表示新值,O(LD)表示旧值,U表示UPDATE操作
CHANGE_VECTOR$$表示修改矢量,用来表示被修改的是哪个或哪几个字段
如果WITH后面跟了ROWID,则物化视图日志中会包含:
M_ROW$$:用来存储发生变化的记录的ROWID
如果WITH后面跟了PRIMARY KEY,则物化视图日志中会包含主键列。
如果WITH后面跟了OBJECT ID,则物化视图日志中会包含:
SYS_NC_OID$:用来记录每个变化对象的对象ID
如果WITH后面跟了SEQUENCE,则物化视图日子中会包含:
SEQUENCE$$:给每个操作一个SEQUENCE号,从而保证刷新时按照顺序进行刷新。
如果WITH后面跟了一个或多个COLUMN名称,则物化视图日志中会包含这些列。
本文出自 “斩月” 博客,谢绝转载!