9i开始,Oracle引入了在线重定义功能,但是bug比较多,10g时,如果数据量比较大,有些特殊场景,也有bug。
因此,前几天有同事需要测试在线重定义的功能,我查了下MOS,做个demo,做一个功能测试,如果生产上在低版本数据库执行在线重定义功能时,请仔细查看MOS上相关的常见问题。
22:28:49 SQL> select * from v$version; BANNER ---------------------------------------------------------------- Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bi PL/SQL Release 10.2.0.4.0 - Production CORE 10.2.0.4.0 Production TNS for Linux: Version 10.2.0.4.0 - Production NLSRTL Version 10.2.0.4.0 - Production 已用时间: 00: 00: 00.01 22:30:24 SQL> select 'www.lunar2013.com' lunar,sysdate from dual; LUNAR SYSDATE -------------------------------- -------------- www.lunar2013.com 05-7月 -14 已用时间: 00: 00: 00.00 22:31:11 SQL>
–创建测试表
CREATE TABLE unpar_table ( a NUMBER, y number, name VARCHAR2(100), date_used date); alter table unpar_table ADD (CONSTRAINT unpar_table_pk PRIMARY KEY (a,y)); -- load table with 1,000,000 rows begin for i in 1 .. 1000 loop for j in 1 .. 1000 loop insert into unpar_table values ( i, j, dbms_random.random, sysdate-j ); end loop; end loop; end; / commit;
–收集统计信息
EXEC DBMS_STATS.gather_table_stats(user, 'unpar_table', cascade => TRUE); SELECT num_rows FROM user_tables WHERE table_name = 'UNPAR_TABLE';
–创建空的分区表
CREATE TABLE par_table (
a NUMBER, y number,
name VARCHAR2(100),date_used DATE)
PARTITION BY RANGE (date_used)
(PARTITION unpar_table_12 VALUES LESS THAN (TO_DATE('10/07/2012', 'DD/MM/YYYY')),
PARTITION unpar_table_15 VALUES LESS THAN (TO_DATE('15/07/2012', 'DD/MM/YYYY')),
PARTITION unpar_table_MX VALUES LESS THAN (MAXVALUE));
–执行Redefinition.can_redef_table,验证unpar_table表是否可以在线重定义,如果不可以会给出建议:
EXEC Dbms_Redefinition.can_redef_table(USER, ‘unpar_table’);
执行这一步的时候,如果缺少如下权限,那么会报如下错误:
第 1 行出现错误:
ORA-06550: 第 1 行, 第 7 列:
PLS-00201: 必须声明标识符 ‘DBMS_REDEFINITION’
ORA-06550: 第 1 行, 第 7 列:
解决方法:
grant execute on dbms_redefinition to lunar;
-- This procedure (DBMS_REDEFINITION.start_redef_table) creates a materialized view based on a CTAS, as we can see below with -- the PREBUILT container table. BEGIN DBMS_REDEFINITION.start_redef_table( uname => USER, orig_table => 'unpar_table', int_table => 'par_table'); END; /
执行这一步的时候,如果缺少如下权限,那么会报如下错误:
第 1 行出现错误:
ORA-01031: 权限不足
ORA-06512: 在 “SYS.DBMS_REDEFINITION”, line 50
ORA-06512: 在 “SYS.DBMS_REDEFINITION”, line 1343
ORA-06512: 在 line 2
解决方法:
grant create any table to lunar;
grant alter any table to lunar;
grant drop any table to lunar;
grant lock any table to lunar;
grant select any table to lunar;
22:16:46 SQL> select mview_name,container_name, build_mode from user_mviews; MVIEW_NAME CONTAINER_NAME BUILD_MOD ------------------------------ ------------------------------ --------- PAR_TABLE PAR_TABLE PREBUILT
–开启DBMS_REDEFINITION.start_redef_table后,向unpar_table表中插入1000行数据
此时,系统会使用mview log来记录该表的变化,可以查询MLOG$_UNPAR_TABLE来确认这一点:
begin
for i in 1001 .. 1010
loop
for j in 1001 .. 1100
loop
insert into unpar_table values ( i, j, dbms_random.random, sysdate-j );
end loop;
end loop;
end;
/
commit;
22:17:07 SQL> select count(*) from MLOG$_UNPAR_TABLE;
COUNT(*)
----------
1000
已用时间: 00: 00: 00.01
22:17:12 SQL> select count(*) from unpar_table;
COUNT(*)
----------
1001000
已用时间: 00: 00: 00.07
22:17:27 SQL> select count(*) from par_table;
COUNT(*)
----------
1000000
已用时间: 00: 00: 00.20
22:17:48 SQL>
–执行dbms_redefinition.sync_interim_table,类似MVIEW FAST REFRESH
–该操作将MLOG$_UNPAR_TABLE的内容同步到par_table,并在同步后purge自己
–在执行dbms_redefinition.finish_redef_table之前,可以执行多次
BEGIN
dbms_redefinition.sync_interim_table(
uname => USER,
orig_table => 'unpar_table',
int_table => 'par_table');
END;
22:18:35 SQL> select count(*) from MLOG$_UNPAR_TABLE;
COUNT(*)
----------
0
已用时间: 00: 00: 00.00
22:22:52 SQL> select count(*) from unpar_table;
COUNT(*)
----------
1001000
已用时间: 00: 00: 00.06
22:22:58 SQL> select count(*) from par_table;
COUNT(*)
----------
1001000
已用时间: 00: 00: 00.06
22:23:03 SQL>
ALTER TABLE par_table ADD (CONSTRAINT par_table_pk2 PRIMARY KEY (a,y));
EXEC DBMS_STATS.gather_table_stats(USER, 'par_table', cascade => TRUE);
–完成在线重定义的操作,切换两个表:
BEGIN
dbms_redefinition.finish_redef_table(
uname => USER,
orig_table => 'unpar_table',
int_table => 'par_table');
END;
/
22:27:49 SQL> select count(*) from MLOG$_UNPAR_TABLE;
select count(*) from MLOG$_UNPAR_TABLE
*
第 1 行出现错误:
ORA-00942: 表或视图不存在
已用时间: 00: 00: 00.00
22:28:02 SQL> select count(*) from unpar_table;
COUNT(*)
----------
1001000
已用时间: 00: 00: 00.06
22:28:10 SQL> select count(*) from par_table;
COUNT(*)
----------
1001000
已用时间: 00: 00: 00.06
22:28:15 SQL>
22:28:32 SQL> SELECT partitioned FROM user_tables WHERE table_name = 'UNPAR_TABLE';
PAR
---
YES
已用时间: 00: 00: 00.02
22:28:34 SQL> SELECT partition_name, num_rows FROM user_tab_partitions WHERE table_name = 'UNPAR_TABLE';
PARTITION_NAME NUM_ROWS
------------------------------ ----------
UNPAR_TABLE_12 274384
UNPAR_TABLE_15 5000
UNPAR_TABLE_MX 721140
已用时间: 00: 00: 00.13
22:28:38 SQL>
22:28:38 SQL> drop TABLE par_table cascade constraints;
表已删除。
已用时间: 00: 00: 00.06
22:28:49 SQL>
