物化视图实践(1)----实现远程数据同步

概念:

首先澄清:Oracle9i 以前叫做快照(snapshot),自9i开始更名为物化视图(materialized view) 。 早先的关键词snapshot被保留并与materialized view同义。

Oracle的物化视图提供了强大的功能,可以用在不同的环境中。在不同的环境中,物化视图的作用也不相同。数据仓库中的物化视图主要用于预先计算并保存表连接或聚集等耗时较多的操作的结果,这样,在执行查询时,就可以避免进行这些耗时的操作,而从快速的得到结果。在数据仓库中,还经常使用查询重写(query rewrite)机制,这样不需要修改原有的查询语句,Oracle会自动选择合适的物化视图进行查询,完全对应用透明。物化视图和表一样可以直接进行查询。物化视图可以基于分区表,物化视图本身也可以分区。除了在数据仓库中使用,物化视图还用于复制、移动计算等方面。

语法:


[sql] view plaincopy在CODE上查看代码片派生到我的代码片

  1. --标*选项为默认  

  2. create materialized view materialized_view_name  

  3. build [immediate|deferred]      --创建方式:*immediate--创建完毕立即同步数据;  

  4.                     --         deferred--等待下次刷新时同步数据(那时也一定会先全部刷新一次的)  

  5. refresh [complete|fast|force|never] --刷新方式:complete--完全刷新  

  6.                     --        fast--快速刷新,依赖基表的快照日志  

  7.                     --        *force--强制刷新,自动判断是否有基表的快照日志可用,然则按fast方式,否则按complete方式  

  8.                     --        never--禁用刷新  

  9. on [commit|demand]          --刷新触发方式:commit--fast刷新方式下可用,基表发生任何DML操作后commit会出发刷新,  

  10.                     --                    注意:不能跨库执行(因为不知道别的库的提交动作)  

  11.                     --                    同库不同用户时,需要授权GRANT ON COMMIT REFRESH to user  

  12.                     --           *demand--在需要时刷新,根据后面设定的起始时间和时间间隔进行刷新,  

  13.                     --                    或者手动调用dbms_mview.refresh过程执行刷新。  

  14. start with (start_date)         --开始时间,如sysdate  

  15. next (interval_date)            --间隔时间,如sysdate+1/(24*60),1分钟间隔  

  16. with [primary key|rowid]        --基于基表的主键或者rowid创建快照,默认 primary key  

  17. enable query rewrite            --是否启用查询重写,需要授权GRANT GLOBAL QUERY REWRITE to user  

  18. as       

  19. select statement;           --基表选取数据的select语句  







同步数据准备


AB两地Oarcle10g数据库,局域网连接,但不能保证365*24贯通。A库为源头库,B库为同步目的库。源头库A中有下表

[sql] view plaincopy在CODE上查看代码片派生到我的代码片

  1. create table SCY_SGT_GTCJ  

  2. (  

  3.   id      VARCHAR2(32) not null,  

  4.   jh      VARCHAR2(21),  

  5.   cjsj    DATE,  

  6.   cc      NUMBER(5,2),  

  7.   cc1     NUMBER(5,2),  

  8.   sxcc1   NUMBER(5,2),  

  9.   xxcc1   NUMBER(5,2),  

  10.   wy      VARCHAR2(4000),  

  11.   dl      VARCHAR2(4000),  

  12.   gl      VARCHAR2(4000),  

  13.   zh      VARCHAR2(4000),  

  14.   bpqscgl VARCHAR2(4000),  

  15.   zj      VARCHAR2(4000),  

  16.   zdzh    NUMBER(6,2),  

  17.   zxzh    NUMBER(6,2),  

  18.   bzgt    VARCHAR2(32),  

  19.   glys    NUMBER(6,2),  

  20.   yggl    NUMBER(6,2),  

  21.   wggl    NUMBER(6,2)  

  22. );  

  23. alter table SCY_SGT_GTCJ  

  24.   add constraint PK_SCY_SGT_GTCJ primary key (ID)  

  25.   using index;  

该表每10分钟采集一个设备的生产数据,目前大约有80台设备投产。因A库的生产重要性,为确保数据采集完整性与及时性,不宜将应用直接搭建在A库上,所以启用B库,但需要解决数据同步的问题。

曾经的做法:用触发器同步数据,在A库基表上实现after触发写入B库,但实测表明,因网络链路的原因,以及本地库其它因素,导致数据丢失情况,日志跟踪记录如下

[plain] view plaincopy在CODE上查看代码片派生到我的代码片

  1. 1   HJSH127-3   2013-12-16 8:55:09  ORA-12541: TNS: 无监听程序...  

  2. 2   HJH86-X71   2013-12-16 8:54:20  ORA-12541: TNS: 无监听程序...  

  3. 3   HJH82-22    2013-12-16 8:54:14  ORA-12541: TNS: 无监听程序...  

  4. 4   HJH82-C6    2013-12-16 8:54:10  ORA-12170: TNS: 连接超时...  

  5. 5   HJSH115-X30 2013-12-16 8:54:10  ORA-12541: TNS: 无监听程序...  

  6. 6   HJSH144     2013-12-16 8:54:05  ORA-12170: TNS: 连接超时...  

  7. 7   HJSH127-7   2013-12-16 8:51:21  ORA-12170: TNS: 连接超时...  

  8. 8   HJH82-27    2013-12-16 8:49:31  ORA-12170: TNS: 连接超时...  

  9. 9   HJH86-P5    2013-12-9 9:00:07   ORA-12170: TNS: 连接超时...  

  10. 10  HJH86-4     2013-12-9 8:33:24   ORA-12170: TNS: 连接超时...  

  11. 11  HJSH115-X35 2013-12-9 7:46:49   ORA-12170: TNS: 连接超时...  

  12. 12  HJSH127-7   2013-12-9 7:40:55   ORA-12170: TNS: 连接超时...  

  13. 13  HJSH125-X3  2013-12-9 7:30:58   ORA-12170: TNS: 连接超时...  

  14. 14  HJSH127-X2  2013-12-9 7:30:58   ORA-12170: TNS: 连接超时...  

  15. 15  HJSH125-2   2013-12-9 7:30:57   ORA-12170: TNS: 连接超时...  

  16. 16  HJSH127-57  2013-12-9 7:25:20   ORA-12170: TNS: 连接超时...  

  17. 17  HJSH127-X22 2013-12-9 7:25:06   ORA-12170: TNS: 连接超时...  

数据丢失造成应用系统的统计分析无法正常实现,所以需要改变数据同步方法――不花钱的方法就是物化视图了,哈哈!

A库上的设定

1.创建表SCY_SGT_GTCJ的快照日志

[sql] view plaincopy在CODE上查看代码片派生到我的代码片

  1. CREATE MATERIALIZED VIEW LOG ON SCY_SGT_GTCJ;  

2.创建用于同步的帐户(可选)

[sql] view plaincopy在CODE上查看代码片派生到我的代码片

  1. create user rt_data  

  2.   identified by user321  

  3.   default tablespace RTDATA  

  4.   temporary tablespace TEMP  

  5.   profile DEFAULT;  

  6. grant resource to rt_data;  

  7. grant connect to rt_data;  

  8. grant select any table to rt_data;  

  9. grant select on SCY_SGT_GTCJ to rt_data;  

B库上的设定

1.创建一个接收同步的帐号

[sql] view plaincopy在CODE上查看代码片派生到我的代码片

  1. Create the user   

  2. create user rt_user  

  3.   identified by user321  

  4.   default tablespace RTDATA  

  5.   temporary tablespace TEMP  

  6.   profile DEFAULT;  

  7. -- Grant/Revoke role privileges   

  8. grant resource to rt_user;  

  9. grant connect to rt_user;  

  10. -- Grant/Revoke system privileges   

  11. grant unlimited tablespace to rt_user;  

  12. grant create database link to rt_user;  

  13. grant create materialized view to rt_user;  

  14. grant select any table to rt_user; --这个权限必须有,否则创建快速刷新的快照会报错权限不足  

2.创建A库的DBLINK

[sql] view plaincopy在CODE上查看代码片派生到我的代码片

  1. create database link gtsj_z23  

  2.   connect to rt_data identified by user321  

  3.   using '(DESCRIPTION =  

  4.     (ADDRESS_LIST =  

  5.       (ADDRESS = (PROTOCOL = TCP)(HOST = 10.68.199.53)(PORT = 1521))  

  6.     )  

  7.     (CONNECT_DATA =  

  8.       (SERVICE_NAME = orcl)  

  9.     )  

  10.   )';  

3.创建快照(物化视图)

[sql] view plaincopy在CODE上查看代码片派生到我的代码片

  1. CREATE MATERIALIZED VIEW SCY_SGT_GTCJ_MV  

  2.    AS SELECT * FROM SCY_SGT_GTCJ@GTSJ_Z23;   

  3. --创建快照完成后,需要耗时片刻同步全部数据,这是必须滴  

  4. --下面可以修改其刷新频率  

  5. ALTER MATERIALIZED VIEW SCY_SGT_GTCJ_MV   

  6.    REFRESH FAST START WITH SYSDATE NEXT SYSDATE+10/(24*60); --10分钟刷新一次  

这里选择的是快速刷新方式,是根据A库快照日志对快照进行INSERT/UPDATE/DELETE操作的,所以一定需要执行第一步操作――创建A库的快照日志。即便我们选择了快速刷新方式,第一次同步数据的时候都会进行完全刷新同步全部数据,如果源表数据很大,请耐心等候。

注意(强烈):看看下面的定义跟上面的有何不同?


[sql] view plaincopy在CODE上查看代码片派生到我的代码片

  1. CREATE MATERIALIZED VIEW SCY_SGT_GTCJ_MV  

  2.    REFRESH FAST START WITH SYSDATE NEXT SYSDATE+10/(24*60) --10分钟刷新一次  

  3.    AS   

  4.    SELECT * FROM SCY_SGT_GTCJ@GTSJ_Z23;   







不建议使用上面语句一次性完成快照的定义,因为A库还在继续采集生产数据的同时,B库完全刷新其数据时,如果源表数据巨大,会造成长时间的读取,并极有可能同步失败。

小结

经过上面的操作,已经能够正常的同步A库数据到B库中,实际运行了一天,暂未发现异常情况。根据度娘情报显示,大数据量表格设计应当采用表分区存储方式,既利于快速查询,也利于历史数据切片管理,综合物化视图的优点,应当可以两者有效结合一下,更加提高同步效率以及后台应用。此话题留待以后再研究了……

下面是一些快照常用的一些方法:

1.查询当前用户下所有快照的刷新摘要信息

[sql] view plaincopy在CODE上查看代码片派生到我的代码片

  1. SELECT What, Last_Date, Next_Date, Total_Time, Broken, Failures, INTERVAL FROM User_Jobs;  

2.删除物化视图

[sql] view plaincopy在CODE上查看代码片派生到我的代码片

  1. DROP MATERIALIZED VIEW SCY_SGT_GTCJ_MV;  

3.发现物化视图定义、刷新错误时,可以使用DBMS_MVIEW.EXPLAIN_MVIEW过程来定位错误,因为这次实践也用到了,这里大概说下。先要建立MV_CAPABILITIES_TABLE表,建表的脚本是$ORACLE_HOME/rdbms/admin/utlxmv.sql,表结构如下:

[sql] view plaincopy在CODE上查看代码片派生到我的代码片

  1. create table MV_CAPABILITIES_TABLE  

  2. (  

  3.   statement_id    VARCHAR2(30),  

  4.   mvowner         VARCHAR2(30),  

  5.   mvname          VARCHAR2(30),  

  6.   capability_name VARCHAR2(30),  

  7.   possible        CHAR(1),  

  8.   related_text    VARCHAR2(2000),  

  9.   related_num     NUMBER,  

  10.   msgno           INTEGER,  

  11.   msgtxt          VARCHAR2(2000),  

  12.   seq             NUMBER  

  13. );--没错,就是无关键字,无索引  

在命令窗口(哦,本人一直使用PL/SQL developer)输入如下命令:

[sql] view plaincopy在CODE上查看代码片派生到我的代码片

  1. EXEC DBMS_MVIEW.EXPLAIN_MVIEW('SELECT * FROM SCY_SGT_GTCJ@GTSJ_Z23','SCY_SGT_GTCJ_MV');  

注意到了么,第一个参数就是定义快照的AS后面的基表查询语句,第二个参数就是快照的名字了。执行完成后,Oracle会自动在MV_CAPABILITIES_TABLE生成一些信息,便于更加详细的了解定义快照中的问题所在。执行下面的查询:

[sql] view plaincopy在CODE上查看代码片派生到我的代码片

  1. SELECT t.Capability_Name, t.Possible, t.Msgno, t.Msgtxt, t.Seq  

  2.   FROM Mv_Capabilities_Table t  

可以看到结果如下:

其实,本次实践中折腾一天最痛苦的就是:某次定义好的物化视图竟然死活不刷新,甚至连完全刷新也不能执行(其实,从上面看下来估计你也会猜到了,咱做了好几次试验,其中某次一不小心有恶果留下了吖抓狂)。

发现当物化视图不能正常刷新,而你又觉得理论上没啥问题时,看看下面

[sql] view plaincopy在CODE上查看代码片派生到我的代码片

  1. SELECT * FROM Dba_Registered_Mviews; --在源头库A上执行,列出当前注册的物化视图  



发现一个与'SCY_SGT_GTCJ_MV具有同样定义的物化视图(但名字不一样,我这里截图晚了,已经被我咔嚓了生气),回想起来是在上次删除快照时因为意外原因而没有在A库上注销掉,那么B库中的物化视图铁定不能更新了,而这个问题用上面的DBMS_MVIEW.EXPLAIN_MVIEW也没能发现。好了,执行下面语句把无效的物化视图注销掉吧(在命令窗口)


[sql] view plaincopy在CODE上查看代码片派生到我的代码片

  1. EXEC DBMS_MVIEW.UNREGISTER_MVIEW('RT_DATA','SCY_SGT_GTCJ','ORCL.REGRESS.RDBMS.DEV.US.ORACLE.COM');  







接下来,回到B库上,drop掉'SCY_SGT_GTCJ_MV,然后再重建,OK,大功告成!!!

――这个经验是度娘N次发骚后寻摸到的,自己都忘记怎么找到门的了!尴尬


最后的验证:Delete or Truncate

听说Oracle10g下面物化视图完全刷新时采用的是delete方式,用下面的命令验证

[sql] view plaincopy在CODE上查看代码片派生到我的代码片

  1. alter session set events '10046 trace name context forever, level 12';  

  2. alter session set sql_trace=true;   

  3. exec dbms_mview.refresh('TEST_02','C');  

  4. alter session set events '10046 trace name context off';  

  5. alter session set sql_trace=false;  

然后到$ORACLE_BASE/admin/$ORACLE_SID/udump查看一下最新的日志文件,里面找一下有删除表格的命令delete test_02。本人表示直接看不懂看这个文件内含啊,太高深了,只是做了一次delete证明,其它都看不懂!

不过最重要的是,完全刷新快照确实是执行了Delete动作,也就意味着表越大,刷新越慢,回滚也越大啊,所以――放弃完全刷新的同步方式吧。


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