oracle物化视图介绍

前言

MView的两大应用方向

本系列文章以实例的方式一步步的说是什么是MView、MView的结构、MView的基本工作过程,以及MView的管理方法。


几个术语的对应

基表
指的是英文里面的Master Table和Master Materialized View,并不只是只一个表,而是创建MView的时候所需要用到的n个表或者是相关的上一级的MView。
MView
就是Materialized View了,物化视图。
源数据库端
Master Site和Master Materialized View Site,指的是基表所在的数据库
MView端
Materialized View Site,MView所在的数据库


什么是MView


MView的基本概念

MView中文名称为物化视图(Materialized View),相对于普通视图来说,MView的不同之处在于MView的结果会保存在一个普通的数据表中,在对MView进行查询的时候不再会对创建 MView的基表进行查询,而是直接查询MView对应的结果表,然后通过定期的刷新机制来更新MView表中的数据。


一个简单的例子

-- 创建一个测试用的表T
USER@orclcreate table t (a intb varchar2(50)constraint pk_tprimary key(a));
Table created.
 
-- 创建对应的MV名为MVT
USER@orclcreate materialized view mvt as select * from t;
Materialized view created.
 
-- 现在往表里面插入一些个数据
USER@orclinsert into t select rownumobject_name fromall_objects;
11449 rows created.
 
USER@orclcommit;
Commit complete.
 
-- 现在我们看一下数据的情况
USER@orclselect count(*) from t;
  
COUNT(*)
--------
--
     11449

 
-- mvt还是没有数据的
USER@orclselect count(*) from mvt;
  
COUNT(*)
--------
--
         0

 
-- 下面对mview做一次刷新看看
USER@orclexec dbms_mview.refresh('mvt');
PL/SQL procedure successfully completed.
 
-- 现在能看到mv里面已经有数据了
USER@orclselect count(*) from mvt;
 
  
COUNT(*)
--------
--
     11449

 
-- 然后我们在看一下表T和MVT的结构可以发现他们两个是一样的
USER@orcldesc t;
 
Name                 Null?    Type
 ------------------
-- -------- -------------
 
A                    NOT NULL NUMBER(38)
 
B                             VARCHAR2(50)
 
USER@orcldesc mvt;
 
Name                 Null?    Type
 ------------------
-- -------- -------------
 
A                    NOT NULL NUMBER(38)
 
B                             VARCHAR2(50)


MView的作用

从上面的例子可以看到我们利用MV创建了一个现有数据表的一个复制,同时通过刷新的方式将两个数据表的数据进行了同步。这个就是我们在复制中利用 MView的最主要的用法,所不同的是在实际应用的环境中表T和MView MVT并不是在同一个机器上,而是分散在两个以上的机器上,同时基表也可能不止一个,可能存在多个。

下面列举了MView在实际中的主要作用:

  • 减轻网络负担:通过MV将数据从一个数据库分发到多个不同的数据库上,通过对多个数据库访问来减轻对单个数据库的网络负担。
  • 搭建分发环境:通过从一个中央数据库将数据分发到多个节点数据库,达到分发数据的目的。
  • 复制数据子集:MV可以进行行级/列级的筛选,这样可以复制需要的那一部分数据。
  • 支持离线计算:MV不需要专用的数据库连接,用户可以按照自己的需求来复制所需要的那一部分数据。


MView的刷新

下面接着说说MView刷新这个事。

MView里面的数据是不会和基表保持实时的同步的,它只是基表在某时时间点(刷新的时间点)的一个一致性的数据的镜像,因此,要保持MView尽可能的和基表同步的话就需要我们定期的对MView进行刷新。


MView刷新的分类

Oracle支持三种种方式的刷新:完全刷新和快速刷新以及强制刷新。

完全刷新(complete refresh)

对一个MView进行全部刷新的时候差不多是将MView重建了,在进行MView全部刷新的时候会现将MView中现有的数据删除(版本在10G或以上)或者TRUNCATE(版本低于9i),然后在根据创建MView时候的查询生成数据插入到MView中。

对于多层的MView来说,当master MView全部刷新之后对应的下一级的MView也需要全部刷新,否则将会收到ORA-12034的错误。

快速刷新(fast refresh)

快速刷新是一种比完全刷新快的多的刷新方式,快速刷新只刷新自上次刷新以来修改的数据,因为快速刷新所要操作的数据量少,使用这种方法能大大的节省带宽.

快速刷新要求在基表上面有MView Log,接着上面给出的例子,我们来给MVT做一个快速刷新。

-- 现在表T上面创建MView Log
-- 如果没有建立MView Log的话要进行快速刷新的话会报错的,大家可以试试
USER@orclcreate materialized view log on t;
Materialized view log created.
 
-- 先看一下我们要修改的数据
USER@orclselect * from t where a=936;
         
A B
--------
-- --------------------------------------------------
       
936 v_$fast_start_servers
 
USER@orclselect * from mvt where a=936;
         
A B
--------
-- --------------------------------------------------
       
936 v_$fast_start_servers
 
-- 接着对表T数据进行一些修改
USER@orclupdate t set b=upper(b) where a=936;
1 row updated.
 
-- 现在T里面的这条数据变成了这样
USER@orclcommit;
Commit complete.
 
USER@orclselect * from t where a=936;
         
A B
--------
-- --------------------------------------------------
       
936 V_$FAST_START_SERVERS
 
-- 接下来就是进行快速刷新了
USER@orclexec dbms_mview.refresh('mvt''F');
PL/SQL procedure successfully completed.
 
-- 现在看MVT里面的结果
USER@orclselect * from mvt where a=936;
         
A B
--------
-- --------------------------------------------------
       
936 V_$FAST_START_SERVERS

快速刷新最大的问题在于如果保证能进行快速刷新,这是对与复杂的查询来说是有些挑战的问题,以后会慢慢的探讨。

强制刷新(force refresh)

当进行强制刷新的时候系统会首先尝试进行快速刷新,如果快速刷新无法进行的时候系统将会进行完全刷新。其实就是一个快速刷新和完全刷新的结合体。


指定刷新方式

既然有那么多种的刷新方式那我们怎么指定他们呢?

在Oracle中有两种方法来制定所用的刷新方式,第一种在上面我们已经看过了,就是在执行刷新MView语句的时候制定刷新方式,比如说

exec dbms_mview.refresh('mvt''F');

用来指定对MView mvt进行快速刷新,将其中的”F”改成”C”就是指定对mvt进行完全刷新了。

exec dbms_mview.refresh('mvt''C');

另外一种方法是直接执行

exec dbms_mview.refresh('mvt');

就是不指定刷新的参数,这个时候MView的刷新方式将是根据创建时候由REFRESH语句指定的刷新方法来进行刷新了,REFRESH语句一共有下面几种使用方法

[refresh [fast | complete | force]
  ......
  ]
  • FAST: 采用增量刷新,只刷新自上次刷新以后进行的修改
  • COMPLETE: 对整个实体化视图进行完全的刷新
  • FORCE(默认): Oracle在刷新时会去判断是否可以进行快速刷新,如果可以则采用Fast方式,否则采用Complete的方式,Force选项是默认选项


什么时候刷新

现在怎么刷新的问题解决了,接下来就是考虑我们什么时候进行刷新了。

我们从上面已经知道我们需要定期的对MView进行刷新以保证基表和MView的数据同步,这个定期的方法就是使用job,同样我们有两种方法来创建刷新MView的job。

使用DBMS_JOB包来创建

-- 提交一个JOB用来刷新MView
USER@orclvariable job1 number;
USER@orclexecdbms_job.submit(:job1,'dbms_mview.refresh(''"user"."mvt"'');',sysdate,'sysdate+1/24');
PL/SQL procedure successfully completed.
 
USER@orclcommit;
Commit complete.
 
-- 查看一下结果
USER@orclselect JOB,NEXT_DATE,NEXT_SEC,INTERVAL,WHAT fromuser_jobs;
       
JOB NEXT_DATE           NEXT_SEC                 INTERVAL                      WHAT
--------
-- ------------------- ------------------------ ------------------------------ ----------------------------------------
        
23 2009-01-13 13:52:14 13:52:14                 sysdate+1/24                  dbms_mview.refresh('"user"."mvt"');

使用这种方法相对下面的方法来说不同之处在于这种方法可以自己指定刷新的语句,这样灵活性相对高一些。

在创建MView的时候指定REFRESH语句

没错,还是REFRESH语句,这个语句的用法还是挺多的,下面列出这个语句的其他用法:

[refresh ......
         [
start with date]
         [
next date]
  ......
  ]
  • START WITH: 第一次刷新时间
  • NEXT: 刷新时间间隔

说明:指定上面两个选项的任意一个都将会在系统中产生一个新的JOB,用来对所建立的MV进行刷新,这个JOB可以从DBA_JOBS查到,同时删除MV之后该JOB也会被删除。下面我们看一个例子:

-- 创建一个MView,并指定刷新时间为sysdate和刷新间隔为一个小时
create materialized view mvt2 
refresh start with sysdate next sysdate+1/24 as select * from t;
Materialized view created.

每两个小时刷新一次

CREATE MATERIALIZED VIEW mvt2
refresh complete
Start With Sysdate Next trunc(sysdate, 'HH24')+1/12
as 
select * from users where isbest=1;

start with指定第一次同步的时间,next则是下次执行时间了
 
-- 现在我们看一下job
-- 请注意这里的WHAT那一栏中MView刷新的代码是不带刷新方式的,也就是说按照创建时候的刷新方式进行刷新
USER@orclselect JOB,NEXT_DATE,NEXT_SEC,INTERVAL,WHAT fromuser_jobs;
JOB NEXT_DATE           NEXT_SEC  INTERVAL      WHAT
-
-- ------------------- --------- ------------- ----------------------------------------
 
21 2009-01-13 13:20:20 13:20:20  sysdate+1/24 dbms_refresh.refresh('"USER"."MVT2"');

另外这里所说的JOB定时刷新只是针对于单个MView来说的,而对于存在多个MView要刷新的时候我们就要开始考虑刷新组了,这个部分以后再慢慢说明。


MView的基本构成

说了这么多的MView的例子,那么MView的结构到底是怎么样的呢?我们先看一副Oracle给出的MView的结构图:


MView架构图(来自Oracle Advance Replication)

现在我们只对一些当前接触到的相关的对象进行说明,其他的部分将在后面的文章中陆续说明:

必要组成部分

  • 基表(MASTER TABLE):这里说的基表不一定只有一个表,也有可能是一个复杂的查询,涉及很多的表,也可能是一个MView。
  • 隐藏的MView对象:对象类型为Materialized View的一个对象,用来维护MView的创建信息。
  • MView表:MView所对应的数据表,这个表也就是一个普通的表,不同的就是这个表是和一个MView相关联的表。
  • 基表的INDEX
  • MView的INDEX:对以用PK建立的MView将会有一个与基表结果一样名字类似的索引,对以使用 ROWID建立的MView将有一个以I_SNAP$_materialized_view_name格式命名的建立在ROWID列上的INDEX。当然 你也可以根据需要自己再创建一些INDEX。
对于需要快速刷新的物化视图

  • MView LOG:要使MView能够被快速刷新的话必须在基表上面创建MView Log,创建MView Log的语法为CREATE MATERIALIZED VIEW LOG ON master_name,MView Log表为Oracle默认以MLOG$_master_name的命名格式建立。
  • 维护MLOG$_的内部触发器:在基表上面的所有DML操作都有一个在基表上的内部触发器记录到MLOG$_master_name中,这个触发器在USER_TRIGGERS是看不到的,不过能够用USER_INTERNAL_TRIGGERS看到。

下面用一个例子来看一下这些个对象

-- 创建一个基表
SQLCREATE TABLE TTT1(A INT PRIMARY KEYB INT);
Table created.
 
-- 以TTT1为基表创建一个可更新的MView
SQLCREATE SNAPSHOT MV_TTT1 FOR UPDATE AS SELECT * FROM TTT1;
Materialized view created.
 
-- 创建MView Log
SQLCREATE MATERIALIZED VIEW LOG ON TTT1;
Materialized view log created.
 
-- 检查MView的对象
SQLSELECT OBJECT_NAMEOBJECT_TYPE FROM ALL_OBJECTS WHEREOBJECT_NAME LIKE '%TTT1%';
OBJECT_NAME                    OBJECT_TYPE
----------------------------
-- -------------------
TTT1                           TABLE
MV_TTT1                        MATERIALIZED VIEW
MV_TTT1                        TABLE
MLOG$_TTT1                     TABLE
USLOG$_MV_TTT1                 TABLE
 
-- 查看MView相关的INDEX
SQLSELECT INDEX_NAME,TABLE_NAME FROM USER_INDEXES WHERE TABLE_NAMELIKE '%TTT1%';
 
INDEX_NAME                     TABLE_NAME
----------------------------
-- ------------------------------
PK_TTT11                       MV_TTT1
PK_TTT1                        TTT1
 
-- 查看内部触发器
SQLSELECT * FROM USER_INTERNAL_TRIGGERS WHERE TABLE_NAME LIKE'%TTT1%';
TABLE_NAME                     INTERNAL_TRIGGER_TY
----------------------------
-- -------------------
MV_TTT1                        UPDATABLE MVIEW LOG
TTT1                           MVIEW LOG

---------------------------------------------------------------------------------
物化视图的使用小结

物化视图的刷新有二类,分别是:on commit on demand。刷新方法有三种分别是:快速(FAST),完全(COMPLETE),强制(FORCE);

ON COMMIT DEMAND 在应用中的问题

ON COMMIT(在提交时)

如果选择on commit ,则在对主表应用上会造成效率降低,这是因为ORACLE在对主表操作提交后马上会进行刷新物化视图操作,这部分时间是也包括在提交时间中。

a) refresh force on commit:中对删,新增记录,物理视图都能真实反映主表的变化。同时这种情况下不用建物化视图日志表。缺点是提交时间长。

b) refresh fast on commit:中对新增或修改能真实反映主表的变化,但对删除则不能反映,必须进行一次完全刷新。

 

ON DEMAND(根据需要)

DEMAND必须用DBMS_MVIEW.REFRESH存储过程建立的JOB去定时刷新物化视图。

a) refresh fast on DEMAND:必须通过调用DBMS_MVIEW.REFRESH存储过程来进行快速刷新反映主表新增情况;但当对主表中的数据删除或修改时,快速刷新则会报错,因此必须调DBMS_MVIEW.REFRESH的完全刷新才能反映。可以通过建立JOB解决。


何时使用物化视图

   在逻辑读数量与返回记录数量之间的比率非常高的时候,用来提高大表汇总与(或)连接的性能。

   在全表扫描或索引范围扫描都不能提供有效性能的时候,用来提高单表访问的性能。基本上,它们是具有平均选择性的访问,从而需要使用分区功能,但是无法利用分区功能的话,使用物化视图就比较合适了。

   在OLTP环境下,对于那些查询频繁但更新相对较少的表比较适合使用物化视图。在这种环境下,为了确保物化视图的数据完全有效,通常会使用基于事务提交的快速杀心模式来刷新物化视图。

   物化视图通常在数据仓库环境中来存储汇总结果。因为首先:数据通常是只读的;因此,在数据库只是用于修改表的时候,刷新物化视图的开销可以被降到最小并通过时间窗口被隔离。其次,在这种环境下,提升的空间可能会非常大。


--------------------------------------------------------------------------

物化视图的命令语法

create materialized view [view_name]
refresh [fast|complete|force]
[
on [commit|demand] |
start with (start_time) next (next_time)
]
as
{创建物化视图用的查询语句}


以上是Oracle创建物化视图(Materialized View,以下简称MV)时的常用语法,各参数的含义如下:

1.refresh [fast|complete|force] 视图刷新的方式:
fast: 增量刷新.假设前一次刷新的时间为t1,那么使用fast模式刷新物化视图时,只向视图中添加t1到当前时间段内,主表变化过的数据.为了记录这种变化, 建立增量刷新物化视图还需要一个物化视图日志表。create materialized view log on (主表名)。
complete:全部刷新。相当于重新执行一次创建视图的查询语句。
force: 这是默认的数据刷新方式。当可以使用fast模式时,数据刷新将采用fast方式;否则使用complete方式。

2.MV数据刷新的时间:
on demand:在用户需要刷新的时候刷新,这里就要求用户自己动手去刷新数据了(也可以使用job定时刷新)
on commit:当主表中有数据提交的时候,立即刷新MV中的数据;
start ……:从指定的时间开始,每隔一段时间(由next指定)就刷新一次;


Oracle的物化视图提供了强大的功能,可以用于预先计算并保存表连接或聚集等耗时较多的操作的结果,这样,在执行查询时,就可以避免进 行这些耗时的操作,而从快速的得到结果。物化视图有很多方面和索引很相似:使用物化视图的目的是为了提高查询性能;物化视图对应用透明,增加和删除物化视 图不会影响应用程序中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。

刷新(Refresh):指当基表发生了DML操作后,物化视图何时采用哪种方式和基表进行同步。刷新的模式有两种:ON DEMAND和ON COMMIT。ON DEMAND指物化视图在用户需要的时候进行刷新,可以手工通过DBMS_MVIEW.REFRESH等方法来进行刷新,也可以通过JOB定时进行刷新。 ON COMMIT指出物化视图在对基表的DML操作提交的同时进行刷新。刷新的方法有四种:FAST、COMPLETE、FORCE和NEVE*。**ST刷 新采用增量刷新,只刷新自上次刷新以后进行的修改。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,来建立不同等级的聚集物化视图。

物化视图的基本操作和使用可以查看网址:http://blog.itpub.net/post/468/13318 相关的东东。我主要说明一下使用物化视图的基本东东。如如何建立在特定的表空间上,这些在其他的物化视图上面几乎都没有任何介绍的。主要以我做的一个例子来操作,
如果对物化视图的基本概念清楚了就比较明白在那里写特定的表空间存储了。

创建物化视图时应先创建存储的日志空间

CREATE MATERIALIZED VIEW LOG ON mv_lvy_levytaxbgtdiv
tablespace ZGMV_DATA --日志保存在特定的表空间
WITH ROWID ;
CREATE MATERIALIZED VIEW LOG ON tb_lvy_levydetaildata
tablespace ZGMV_DATA --日志保存在特定的表空间
WITH ROWID,sequence(LEVYDETAILDATAID);
CREATE MATERIALIZED VIEW LOG ON tb_lvy_levydata
tablespace ZGMV_DATA --日志保存在特定的表空间
WITH rowid,sequence(LEVYDATAID);
然后创建物化视图
--创建物化视图
create materialized view MV_LVY_LEVYDETAILDATA
TABLESPACE ZGMV_DATA --保存表空间
BUILD DEFERRED --延迟刷新不立即刷新
refresh force --如果可以快速刷新则进行快速刷新,否则完全刷新
on demand --按照指定方式刷新
start with to_date('24-11-2005 18:00:10', 'dd-mm-yyyy hh24:mi:ss') --第一次刷新时间
next TRUNC(SYSDATE+1)+18/24 --刷新时间间隔
as
SELECT levydetaildataid, detaildatano, taxtermbegin, taxtermend,
......
ROUND(taxdeduct * taxpercent1, 2) - ROUND(taxdeduct * taxpercent2, 2) -
ROUND(taxdeduct * taxpercent3, 2) - ROUND(taxdeduct * taxpercent4, 2) -
ROUND(taxdeduct * taxpercent5, 2) taxdeduct, ROUND(taxfinal * taxpercent1, 2) -
ROUND(taxfinal * taxpercent2, 2) - ROUND(taxfinal * taxpercent3, 2) -
ROUND(taxfinal * taxpercent4, 2) - ROUND(taxfinal * taxpercent5, 2) taxfinal,
a.levydataid, a.budgetitemcode, taxtypecode,
......
FROM tb_lvy_levydetaildata a, tb_lvy_levydata c, MV_LVY_LEVYTAXBGTDIV b
WHERE a.levydataid = c.levydataid
AND a.budgetdistrscalecode = b.budgetdistrscalecode
AND a.budgetitemcode = b.budgetitemcode
AND c.incomeresidecode = b.rcvfisccode
AND C.TAXSTATUSCODE='08'
AND C.NEGATIVEFLAG!='9'
删除物化视图日志
--删除物化视图:
--删除日志: DROP materialized view log on mv_lvy_levytaxbgtdiv;
DROP materialized view log on tb_lvy_levydetaildata;
DROP materialized view log on tb_lvy_levydata;
--删除物化视图 drop materialized view MV_LVY_LEVYDETAILDATA;
--基本和对表的操作一致 --物化视图由于是物理真实存在的,故可以创建索引。
创建方式和对普通表创建方式相同,就不在重复写了。


原文地址:https://www.cnblogs.com/JSD1207ZX/p/9386277.html