http://www.dbabeta.com/2009/mview_step_by_step_01.html
前言
-
MView的两大应用方向
- 一是用于数据库的复制,这个在Oracle文档《Advanced Replication》中有详细的描述。
- 另一个是用于数据仓库,同样Oracle文档《Oracle Database Data Warehousing Guide》中也有详细的描述。
本系列文章以实例的方式一步步的说是什么是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表中的数据。
一个简单的例子
USER @ orcl > create table t ( a int , b varchar2 ( 50 ) , constraint pk_t primary key ( a )) ;
Table created .
-- 创建对应的MV名为MVT
USER @ orcl > create materialized view mvt as select * from t ;
Materialized view created .
-- 现在往表里面插入一些个数据
USER @ orcl > insert into t select rownum , object_name from all_objects ;
11449 rows created .
USER @ orcl > commit ;
Commit complete .
-- 现在我们看一下数据的情况
USER @ orcl > select count ( * ) from t ;
COUNT ( * )
-------- --
11449
-- mvt还是没有数据的
USER @ orcl > select count ( * ) from mvt ;
COUNT ( * )
-------- --
0
-- 下面对mview做一次刷新看看
USER @ orcl > exec dbms_mview . refresh ( ' mvt ' ) ;
PL / SQL procedure successfully completed .
-- 现在能看到mv里面已经有数据了
USER @ orcl > select count ( * ) from mvt ;
COUNT ( * )
-------- --
11449
-- 然后我们在看一下表T和MVT的结构可以发现他们两个是一样的
USER @ orcl > desc t ;
Name Null ? Type
------------------ -- -------- -------------
A NOT NULL NUMBER ( 38 )
B VARCHAR2 ( 50 )
USER @ orcl > desc 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做一个快速刷新。
-- 如果没有建立MView Log的话要进行快速刷新的话会报错的,大家可以试试
USER @ orcl > create materialized view log on t ;
Materialized view log created .
-- 先看一下我们要修改的数据
USER @ orcl > select * from t where a = 936 ;
A B
-------- -- --------------------------------------------------
936 v_ $ fast_start_servers
USER @ orcl > select * from mvt where a = 936 ;
A B
-------- -- --------------------------------------------------
936 v_ $ fast_start_servers
-- 接着对表T数据进行一些修改
USER @ orcl > update t set b = upper ( b ) where a = 936 ;
1 row updated .
-- 现在T里面的这条数据变成了这样
USER @ orcl > commit ;
Commit complete .
USER @ orcl > select * from t where a = 936 ;
A B
-------- -- --------------------------------------------------
936 V_ $ FAST_START_SERVERS
-- 接下来就是进行快速刷新了
USER @ orcl > exec dbms_mview . refresh ( ' mvt ' , ' F ' ) ;
PL / SQL procedure successfully completed .
-- 现在看MVT里面的结果
USER @ orcl > select * from mvt where a = 936 ;
A B
-------- -- --------------------------------------------------
936 V_ $ FAST_START_SERVERS
快速刷新最大的问题在于如果保证能进行快速刷新,这是对与复杂的查询来说是有些挑战的问题,以后会慢慢的探讨。
强制刷新(force refresh)
当进行强制刷新的时候系统会首先尝试进行快速刷新,如果快速刷新无法进行的时候系统将会进行完全刷新。其实就是一个快速刷新和完全刷新的结合体。
指定刷新方式
既然有那么多种的刷新方式那我们怎么指定他们呢?
在Oracle中有两种方法来制定所用的刷新方式,第一种在上面我们已经看过了,就是在执行刷新MView语句的时候制定刷新方式,比如说
用来指定对MView mvt进行快速刷新,将其中的”F”改成”C”就是指定对mvt进行完全刷新了。
另外一种方法是直接执行
就是不指定刷新的参数,这个时候MView的刷新方式将是根据创建时候由REFRESH语句指定的刷新方法来进行刷新了,REFRESH语句一共有下面几种使用方法
......
]
- FAST: 采用增量刷新,只刷新自上次刷新以后进行的修改
- COMPLETE: 对整个实体化视图进行完全的刷新
- FORCE(默认): Oracle在刷新时会去判断是否可以进行快速刷新,如果可以则采用Fast方式,否则采用Complete的方式,Force选项是默认选项
什么时候刷新
现在怎么刷新的问题解决了,接下来就是考虑我们什么时候进行刷新了。
我们从上面已经知道我们需要定期的对MView进行刷新以保证基表和MView的数据同步,这个定期的方法就是使用job,同样我们有两种方法来创建刷新MView的job。
使用DBMS_JOB包来创建
USER @ orcl > variable job1 number ;
USER @ orcl > exec dbms_job . submit ( : job1 , ' dbms_mview.refresh( '' "user"."mvt" '' ); ' , sysdate , ' sysdate+1/24 ' ) ;
PL / SQL procedure successfully completed .
USER @ orcl > commit ;
Commit complete .
-- 查看一下结果
USER @ orcl > select JOB , NEXT_DATE , NEXT_SEC , INTERVAL , WHAT from user_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语句,这个语句的用法还是挺多的,下面列出这个语句的其他用法:
[ start with date ]
[ next date ]
......
]
- START WITH: 第一次刷新时间
- NEXT: 刷新时间间隔
说明:指定上面两个选项的任意一个都将会在系统中产生一个新的JOB,用来对所建立的MV进行刷新,这个JOB可以从DBA_JOBS查到,同时删除MV之后该JOB也会被删除。下面我们看一个例子:
USER @ orcl > create materialized view mvt2 refresh start with sysdate next sysdate + 1 / 24 as select * from t ;
Materialized view created .
-- 现在我们看一下job
-- 请注意这里的WHAT那一栏中MView刷新的代码是不带刷新方式的,也就是说按照创建时候的刷新方式进行刷新
USER @ orcl > select JOB , NEXT_DATE , NEXT_SEC , INTERVAL , WHAT from user_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看到。
下面用一个例子来看一下这些个对象
SQL > CREATE TABLE TTT1 ( A INT PRIMARY KEY , B INT ) ;
Table created .
-- 以TTT1为基表创建一个可更新的MView
SQL > CREATE SNAPSHOT MV_TTT1 FOR UPDATE AS SELECT * FROM TTT1 ;
Materialized view created .
-- 创建MView Log
SQL > CREATE MATERIALIZED VIEW LOG ON TTT1 ;
Materialized view log created .
-- 检查MView的对象
SQL > SELECT OBJECT_NAME , OBJECT_TYPE FROM ALL_OBJECTS WHERE OBJECT_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
SQL > SELECT INDEX_NAME , TABLE_NAME FROM USER_INDEXES WHERE TABLE_NAME LIKE ' %TTT1% ' ;
INDEX_NAME TABLE_NAME
---------------------------- -- ------------------------------
PK_TTT11 MV_TTT1
PK_TTT1 TTT1
-- 查看内部触发器
SQL > SELECT * FROM USER_INTERNAL_TRIGGERS WHERE TABLE_NAME LIKE ' %TTT1% ' ;
TABLE_NAME INTERNAL_TRIGGER_TY
---------------------------- -- -------------------
MV_TTT1 UPDATABLE MVIEW LOG
TTT1 MVIEW LOG
作者:马齿苋 | 链接:http://www.dbabeta.com/2009/mview_step_by_step_01.html