数据迁移中有一种解决方案很有亮点,如果表的数据量大,迁移涉及的表不多,同时对于维护时间有要求的情况下,物化视图的prebuilt方式就是一种很不错的选择。
大体的步骤和方法如下:
假设源环境是test_source,目标环境是test_target
在源环境中test_source的操作如下:
Create table test_mv as select *from all_objects ;
alter table test_mv modify(object_id primary key);
create materialized view log on test; 这个地方需要注意是主键,with rowid的方式是不可以的
目标环境test_target的操作如下:
创建db link
然后创建表,同步表结构即可
create table test_mv as select * from test_mv@prdb where 1=2;
然后创建物化视图,和表同名
create materialized view test_mv on prebuilt table refresh fast as select * from test_mv@test_source;
第一次需要全量刷新数据,也就意味着一次全量,以后都是增量
exec dbms_mview.refresh(‘TEST_MV’,‘FAST’); -- 刷新数据
确认数据同步正常,删除物化视图即可
Drop materialized view test_mv;
需要补充的是创建快速刷新的物化视图,使用如下with rowid的方式是可行的,但是在prebuilt table的情况下,这个还无法支持。
create materialized view test_mv on prebuilt table refresh fast with rowid as select * from test_mv@test_source;
这个其实也可以理解。因为源环境和目标环境是完全不同的数据库环境,rowid无法固定,只能通过主键的方式来定位。
而如果我们进一步细想,如果是同一个数据库中要做这种类似的操作,好像实践意义不大,谁会无聊的自己复制自己的数据,然后不断刷新。
其实不然,大名鼎鼎的在线重定义就是如此。我们来捋一捋里面的一些东西。
在线重定义需要有一个检查步骤。
EXEC dbms_redefinition.can_redef_table('N1','TAB_PART_ONE_PAR',1);
默认是需要使用PK,否则会报出错误ORA-12089: cannot online redefine table "N1"."TAB_PART_ONE_PAR" with no primary key
而一种改进思路就是使用rowid的方式,改进成为下面的形式即可。
EXEC dbms_redefinition.can_redef_table('N1','TAB_PART_ONE_PAR',dbms_redefinition.cons_use_rowid);
在同一个数据库中,这样做是没有问题的,我们完全可以通过rowid定位到具体的一行数据。
而在线重定义为什么能够始终保持重定义的过程中,源表始终可用,其实内部就是在通过物化视图日志来得到增量的数据变化,重定义过程中DML操作依旧是在源表上进行,对于源表要说完全没有影响那是不可能的,但是能够保证数据访问,更新操作始终可进行,这个意义就大大不同了。为什么一个表可以在线修改为分区表,为什么一个表添加若干个字段始终会保持业务不受影响。因为在线重定义的本质就是物化视图的prebuilt,比如我们要把一个普通表改为分区表,那么普通表就是源表,分区表就是目标表。
在线重定义的过程中会从源表中复制数据到目标表,类似于insert into 目标表 select *from 源表,或者dbms_mview.refresh('目标表‘,'C')这种方式。
而增量的数据则会写入物化视图日志,可以在后续不断去刷新缩小数据的差异。这个过程就是无话视图的增量刷新,类似于dbms_mview.refresh('目标表‘,'F');
而在最后确认无误的情况下,能够删除和表同名的物化视图,则停止了数据的更新,这样目标表也释放出来了,这个时候需要做的就是,复制源表的数据字典信息,和目标表替换。整个过程都给完整的衔接起来了。
如此看来,在线重定义的过程真是好玩,和物化视图prebuilt方式较大的差别就是数据字典信息的复制,而在多数据库环境中,源库,目标库的数据访问信息本就不同,所以也就无需考虑这个因素了,大道至简,其实很多思路都是相通。