在线重定义是怎么实现的
前段时间在ITPUB上看到有人问在线重定义是怎么实现的,一直没时间整理。
通常在线重定义有以下几个部分:
dbms_redefinition.can_redef_table dbms_redefinition.start_redef_table dbms_redefinition.sync_interim_table dbms_redefinition.finish_redef_table
- dbms_redefinition.can_redef_table:检查是否满足在线重定义的先决条件,如果没有报错,表示检查通过,如果检查没有通过,错误信息会提示在哪出的问题。
- dbms_redefinition.start_redef_table:启动在线重定义。
- dbms_redefinition.sync_interim_table:同步数据。
- dbms_redefinition.finish_redef_table:结束在线重定义。
下面是实验过程及追踪后的trace部分内容,通过追踪,看看ORACLE是怎样实现在线重定义的。
实验环境:
win7 64位操作系统
oracle 11.2.0.1.0 for windows X86_64
步骤1.创建测试表并插入测试数据
SQL> create table t_test(id number,code varchar2(5),identifier varchar2(20)); 表已创建。 SQL> insert into t_test values(1,'01','01-01-0001-000001'); 已创建 1 行。 SQL> insert into t_test values(2,'02','02-01-0001-000001'); 已创建 1 行。 SQL> insert into t_test values(3,'03','03-01-0001-000001'); 已创建 1 行。 SQL> insert into t_test values(4,'04','04-01-0001-000001'); 已创建 1 行。 SQL> commit; 提交完成。 SQL> create table t_temp(id number,code varchar2(5), identifier varchar2(20)) 2 partition by list (code) 3 (partition part01 values('01'), 4 partition part02 values('02'), 5 partition part03 values('03'), 6 partition part04 values('04'), 7 partition part05 values(default) 8 ); 表已创建。 SQL> alter table t_temp add constraint pk_temp_id primary key (id); 表已更改。 SQL> select * from tab; TNAME TABTYPE CLUSTERID ------------------------------ ------- ---------- T_TEMP TABLE T_TEST TABLE
步骤2.先决条件检查
SQL> exec dbms_redefinition.can_redef_table('stream', 't_test'); PL/SQL 过程已成功完成。
查看trace文件会看到,该过程ORACLE做的都是select操作,在检查是否支持在线重定义,下面是摘自trace文件的SQL语句。
SQL ID: csq97ktzjj1rz Plan Hash: 0 BEGIN dbms_redefinition.can_redef_table('stream', 't_test'); END; SQL ID: cjk1ffy5kmm5s Plan Hash: 1964104430 select obj# from oid$ where user#=:1 and oid$=:2 SQL ID: 2yuyykvzhrp4t Plan Hash: 901817615 SELECT redef_id FROM sys.redef_object$ WHERE obj_type = :1 AND obj_owner = :2 AND obj_name = :3 AND rownum = 1 SQL ID: 1gu8t96d0bdmu Plan Hash: 2035254952 select t.ts#,t.file#,t.block#,nvl(t.bobj#,0),nvl(t.tab#,0),t.intcols, nvl(t.clucols,0),t.audit$,t.flags,t.pctfree$,t.pctused$,t.initrans, t.maxtrans,t.rowcnt,t.blkcnt,t.empcnt,t.avgspc,t.chncnt,t.avgrln, t.analyzetime,t.samplesize,t.cols,t.property,nvl(t.degree,1), nvl(t.instances,1),t.avgspc_flb,t.flbcnt,t.kernelcols,nvl(t.trigflag, 0), nvl(t.spare1,0),nvl(t.spare2,0),t.spare4,t.spare6,ts.cachedblk,ts.cachehit, ts.logicalread from tab$ t, tab_stats$ ts where t.obj#= :1 and t.obj# = ts.obj# (+) SQL ID: 7ng34ruy5awxq Plan Hash: 2606284882 select i.obj#,i.ts#,i.file#,i.block#,i.intcols,i.type#,i.flags,i.property, i.pctfree$,i.initrans,i.maxtrans,i.blevel,i.leafcnt,i.distkey,i.lblkkey, i.dblkkey,i.clufac,i.cols,i.analyzetime,i.samplesize,i.dataobj#, nvl(i.degree,1),nvl(i.instances,1),i.rowcnt,mod(i.pctthres$,256), i.indmethod#,i.trunccnt,nvl(c.unicols,0),nvl(c.deferrable#+c.valid#,0), nvl(i.spare1,i.intcols),i.spare4,i.spare2,i.spare6,decode(i.pctthres$,null, null,mod(trunc(i.pctthres$/256),256)),ist.cachedblk,ist.cachehit, ist.logicalread from ind$ i, ind_stats$ ist, (select enabled, min(cols) unicols, min(to_number(bitand(defer,1))) deferrable#,min(to_number(bitand(defer,4))) valid# from cdef$ where obj#=:1 and enabled > 1 group by enabled) c where i.obj#=c.enabled(+) and i.obj# = ist.obj#(+) and i.bo#=:1 order by i.obj# SQL ID: 5n1fs4m2n2y0r Plan Hash: 299250003 select pos#,intcol#,col#,spare1,bo#,spare2,spare3 from icol$ where obj#=:1 SQL ID: 83taa7kaw59c1 Plan Hash: 3765558045 select name,intcol#,segcol#,type#,length,nvl(precision#,0),decode(type#,2, nvl(scale,-127/*MAXSB1MINAL*/),178,scale,179,scale,180,scale,181,scale,182, scale,183,scale,231,scale,0),null$,fixedstorage,nvl(deflength,0),default$, rowid,col#,property, nvl(charsetid,0),nvl(charsetform,0),spare1,spare2, nvl(spare3,0) from col$ where obj#=:1 order by intcol# SQL ID: 3w4qs0tbpmxr6 Plan Hash: 1224215794 select con#,obj#,rcon#,enabled,nvl(defer,0),spare2,spare3 from cdef$ where robj#=:1 SQL ID: gx4mv66pvj3xz Plan Hash: 1932954096 select con#,type#,condlength,intcols,robj#,rcon#,match#,refact,nvl(enabled,0), rowid,cols,nvl(defer,0),mtime,nvl(spare1,0),spare2,spare3 from cdef$ where obj#=:1 SQL ID: 53saa2zkr6wc3 Plan Hash: 3954488388 select intcol#,nvl(pos#,0),col#,nvl(spare1,0) from ccol$ where con#=:1 SQL ID: 9qj6r53cwban Plan Hash: 2358287056 select c.name from sys.con$ c where c.con# = :1 SQL ID: br71g8xazf0kf Plan Hash: 626680409 select 1 from sys.cdc_change_tables$ where change_table_schema = :1 and change_table_name = :2 SQL ID: 9gkq7rruycsjp Plan Hash: 3362549386 select parttype, partcnt, partkeycols, flags, defts#, defpctfree, defpctused, definitrans, defmaxtrans, deftiniexts, defextsize, defminexts, defmaxexts, defextpct, deflists, defgroups, deflogging, spare1, mod(spare2, 256) subparttype, mod(trunc(spare2/256), 256) subpartkeycols, mod(trunc(spare2/65536), 65536) defsubpartcnt, mod(trunc(spare2/4294967296), 256) defhscflags, mod(spare3, 256) interval_dty, rowid, defmaxsize from partobj$ where obj# = :1 SQL ID: 90t64pvhxmza8 Plan Hash: 4233067210 select 1 from sys.mlog$ where mowner = :1 and log = :2 SQL ID: 96g93hntrzjtr Plan Hash: 2239883476 select /*+ rule */ bucket_cnt, row_cnt, cache_cnt, null_cnt, timestamp#, sample_size, minimum, maximum, distcnt, lowval, hival, density, col#, spare1, spare2, avgcln from hist_head$ where obj#=:1 and intcol#=:2
可以看到,ORACLE进行了一大堆的检查操作,其中也包括物化视图相关的检查,可以推测ORACLE的在线重定义是使用物化视图实现数据同步的,这些应该在同步数据的时候会看到。
步骤3.开始在线重定义
SQL> exec dbms_redefinition.start_redef_table('stream', 't_test', 't_temp'); PL/SQL 过程已成功完成。
此时查看t_temp表可以看到数据已经同步过来。
SQL> select * from t_temp; ID CODE IDENTIFIER ---------- ----- -------------------- 1 01 01-01-0001-000001 2 02 02-01-0001-000001 3 03 03-01-0001-000001 4 04 04-01-0001-000001
此时向t_test表插入数据,不会同步到t_temp表,这个过程不会影响对t_test表的正常操作。
SQL> insert into t_test values(5,'05','05-01-0001-000001'); 已创建 1 行。 SQL> commit; 提交完成。 SQL> select * from t_test; ID CODE IDENTIFIER ---------- ----- -------------------- 1 01 01-01-0001-000001 2 02 02-01-0001-000001 3 03 03-01-0001-000001 4 04 04-01-0001-000001 5 05 05-01-0001-000001 SQL> select * from t_temp; ID CODE IDENTIFIER ---------- ----- -------------------- 1 01 01-01-0001-000001 2 02 02-01-0001-000001 3 03 03-01-0001-000001 4 04 04-01-0001-000001
查看trace文件,会看到ORACLE干了好多的活,这次不只是select了,下面摘自trace文件的SQL语句,select语句就不摘录了:
SQL ID: a37q3yk2aa9bf Plan Hash: 0 BEGIN dbms_redefinition.start_redef_table('stream', 't_test', 't_temp'); END; SQL ID: 4m7m0t6fjcs5x Plan Hash: 1935744642 --可以看到这里使用到了序列 update seq$ set increment$=:2,minvalue=:3,maxvalue=:4,cycle#=:5,order$=:6, cache=:7,highwater=:8,audit$=:9,flags=:10 where obj#=:1 SQL ID: 45448dcmnf2a4 Plan Hash: 0 --创建物化视图日志 create table "STREAM"."MLOG$_T_TEST" ("ID" NUMBER, snaptime$$ date, dmltype$$ varchar2(1), old_new$$ varchar2(1), change_vector$$ raw(255), xid$$ number) pctfree 10 pctused 30 SQL ID: 0r1prja1au35b Plan Hash: 0 --创建可更新物化视图日志 CREATE GLOBAL TEMPORARY TABLE "STREAM"."RUPD$_T_TEST" ("ID" NUMBER, dmltype$$ varchar2(1), snapid integer, change_vector$$ raw(255)) ON COMMIT PRESERVE ROWS SQL ID: 8f0wqd1ffcw8q Plan Hash: 0 --将数据同步到T_TEMP表 INSERT INTO "STREAM"."T_TEMP"("ID","CODE","IDENTIFIER") SELECT "T_TEST"."ID", "T_TEST"."CODE","T_TEST"."IDENTIFIER" FROM "STREAM"."T_TEST" "T_TEST"
上面只摘取部分trace内容,可见在这个过程中,ORACLE用到了物化视图。
步骤4.同步数据
下面再看下同步数据的过程。
SQL> exec dbms_redefinition.sync_interim_table('stream', 't_test', 't_temp'); PL/SQL 过程已成功完成。 SQL> select * from t_test; ID CODE IDENTIFIER ---------- ----- -------------------- 1 01 01-01-0001-000001 2 02 02-01-0001-000001 3 03 03-01-0001-000001 4 04 04-01-0001-000001 5 05 05-01-0001-000001 SQL> select * from t_temp; ID CODE IDENTIFIER ---------- ----- -------------------- 1 01 01-01-0001-000001 2 02 02-01-0001-000001 3 03 03-01-0001-000001 4 04 04-01-0001-000001 5 05 05-01-0001-000001
可见,在同步后,新插入的数据也同步到了T_TEMP表中,下面看下trace文件内容。
SQL ID: 1jvfq4a0r1yfu --开始同步 Plan Hash: 0 BEGIN dbms_redefinition.sync_interim_table('stream', 't_test', 't_temp'); END; SQL ID: 3dbyq4rdncaj8 Plan Hash: 0 --将上文插入到T_TEST表的数据同步到T_TEMP INSERT INTO "STREAM"."T_TEMP" ("ID","CODE","IDENTIFIER") VALUES (:1,:2,:3)
步骤5.结束重定义
同步过程就是利用物化视图将新对T_TEST表的操作同步到T_TEMP表中,下面再看下finish的过程。
SQL ID: 1ku4fhcg4sfwd Plan Hash: 0 BEGIN dbms_redefinition.finish_redef_table('stream', 't_test', 't_temp'); END;
在看下相关的trace会发现,在这个过程中,ORACLE在做一些delete和drop操作。
SQL ID: 4sa26ghd5gdvz Plan Hash: 0 UPDATE "STREAM"."T_TEMP" SET "ID" = :1,"CODE" = :2,"IDENTIFIER" = :3 WHERE "ID" = :1 SQL ID: 9n6hzq6rct7s8 Plan Hash: 0 drop materialized view "STREAM"."T_TEMP" SQL ID: fnncq952g4ux5 Plan Hash: 0 drop view "STREAM"."T_TEMP" SQL ID: 8qpg5jxwh8pws Plan Hash: 0 drop table "STREAM"."MLOG$_T_TEST" purge
这样ORACLE在打扫完战场以后,就完成了在线重定义操作,根据这个实验可以看出,ORACLE的在线重定义是使用物化视图实现的,当然整个过程并没这么简单,本文只摘取了部分trace内容,有想深入研究的朋友可以仔细分析下trace文件。