用Trigger为MView手动增加时间戳

用Trigger为MView手动增加时间戳
用Trigger为MView手动增加时间戳
 
 
    很多人都遇到过这样的问题:源数据库里的表没有时间戳,或者有时间戳的字段但没有严格执行,而历史数据又可能会经常性得被修改。这对于ETL数据抽取来说将是一个很大的问题,特别是对于不能动源库的情况下,很难解决这个问题。最近又因为这个问题,考虑了很久,最后打算在MView同步数据的基础上,通过Trigger来手动增加时间戳。
 
    考虑对MView操作的原因是因为现有的数据同步就是用MView做的,据说用Stream同步数据也可以用类似的办法添加时间戳的,这个相关的问题以后再研究,讲一下MView下的操作。
 
    首先MView有一些天然的限制,因为最初我考虑的是在建MView的时候就添加一个SYSDATE的字段,这样每次同步就会自动将同步时的sysdate也加入到新的物化视图中,但是这个尝试失败了,因为增量(Fast)更新不支持复杂表结构,而Oracle认为新增字段的表都属于复杂表,会报错如下:
    ORA-12015: cannot create a fast refresh materialized view from a complex query
    然后又希望能够通过物化视图的on commit刷新模式对表进行刷新,这样可以直接查询ora_rowscn来判断某行的更新时间,但是很遗憾,on commit的刷新模式只针对同库下的更新,不支持远程同步,所以没办法只能用Trigger来自己手工增加时间戳。具体的实验步骤如下:
 
 
 
1、在源库中建立表t1,并添加mv log:
 
SQL> create table t1(a int primary key,b int);
 
Table created.
 
SQL> insert into t1 values(1,2);
 
1 row created.
 
SQL> insert into t1 values(3,4);
 
1 row created.
 
SQL> commit;
 
Commit complete.
 
SQL> select * from t1;
 
         A          B
---------- ----------
         1          2
         3          4
 
SQL> create materialized view log on t1 with primary key;
 
Materialized view log created.
 
 
2、在新 库上添加源库的DB LINK:
 
SQL> create database link wxq_db
  2  connect to wangxiaoqi identified by wangxiaoqi
  3  using '(DESCRIPTION =
  4      (ADDRESS_LIST =
  5        (ADDRESS = (PROTOCOL = TCP)(HOST = 10.20.1.127)(PORT = 1521))
  6      )
  7      (CONNECT_DATA =
  8        (SERVICE_NAME = devWXQowb)
  9       )
10      )';

Database link created.
 
SQL> select * from t1@ wxq_db ;
 
             A              B
-------------- --------------
             1              2
             3              4
 
 
3、在新库创建物化视图,设置增量刷新
 
SQL> create materialized view wxq_t1
  2  build deferred
  3  refresh fast
  4  on demand
  5  with primary key
  6  as
  7  select * from t1@wxq_db ;

Materialized view created.
 
SQL> select * from wxq_t1;
 
no rows selected
 
--第一次必须要全量刷新
 
SQL> exec dbms_mview.refresh('wxq_t1','complete');
 
PL/SQL procedure successfully completed.
 
SQL> select * from wxq_t1;
 
         A          B
---------- ----------
         1          2
         3          4
 
 
4、在新库创建关于表T1的Trigger:
 
SQL> create table t1_log(a int,c_flag varchar2(2),modifydate date);
 
Table created.
SQL> create or replace trigger t1_tgr after update or insert or delete on wxq_t1
  2     referencing old as oldrow new as newrow for each row
  3  begin
  4     if inserting then
  5     insert into t1_log values(:newrow.a,'I',sysdate);
  6     end if;
  7     if updating then
  8     insert into t1_log values(:oldrow.a,'U',sysdate);
  9     end if;
10     if deleting then
11     insert into t1_log values(:oldrow.a,'D',sysdate);
12     end if;
13  end;
14  /

Trigger created.
 
 
5、来测试一下在源库中进行插入、删除、修改操作
 
SQL> select * from t1;
 
         A          B
---------- ----------
         1          2
         3          4
 
SQL> insert into t1 values(10,20);
 
1 row created.
 
SQL> update t1 set b=40 where a=3;
 
1 row updated.

SQL> delete from t1 where a=1;
 
1 row deleted.
SQL> commit;
 
Commit complete.
 
SQL> select * from t1;
 
         A          B
---------- ----------
        10         20
         3         40
 
SQL> column change_vector$$ format a20
SQL> select * from mlog$_t1;
 
         A SNAPTIME$$ DM OL CHANGE_VECTOR$$
---------- ---------- -- -- --------------------
        10 4000-01-01 I  N  FE
         3 4000-01-01 U  U  04
         1 4000-01-01 D  O  00
 
 
--然后在新库中查看时候生效
 
SQL> select * from t1_log;
 
no rows selected
 
SQL> exec dbms_mview.refresh('wxq_t1','fast');
 
PL/SQL procedure successfully completed.
 
SQL> select * from t1_log;
 
         A C_ MODIFYDATE
---------- -- ----------
         1 D  2009-06-18
        10 I  2009-06-18
         3 U  2009-06-18
 
 
6、创建最终视图,方便实际操作:
 
SQL> create or replace view t1 as
  2    select wxq_t1.a,wxq_t1.b,t1_log.c_flag,t1_log.modifydate
  3      from wxq_t1,t1_log
  4     where wxq_t1.a = t1_log.a
  5       and t1_log.c_flag in ('I','U')
  6    union all
  7    select t1_log.a,wxq_t1.b,t1_log.c_flag,t1_log.modifydate
  8      from wxq_t1,t1_log
  9     where t1_log.a = wxq_t1.a(+)
10       and t1_log.c_flag = 'D';
 
View created.
 
SQL> select * from t1;
 
         A          B C_ MODIFYDATE
---------- ---------- -- ----------
        10         20 I  2009-06-18
         3         40 U  2009-06-18
         1            D  2009-06-18
 
 
    这样就创建完成了,不但为新记录添加了时间戳,而且也增加了被删除记录的时间(被删除记录只剩下主键和时间字段信息)。不过这个方法有些过于繁琐,只能在对少数表加时间戳的情况下使用,而不能全库操作,而且针对每一个表都需要建一个trigger,效率也是个问题。但是好处是创建之后对于前台查询时完全透明的,注意最终的查询view名称是与源库的表名一致的,这样的封装性对前台操作的感觉非常好。
 
 
 
 

你可能感兴趣的:(用Trigger为MView手动增加时间戳)