Parnassus data recovery manager for oracle database user guide v0.3
了解Oracle在线重定义online redefinition
1. 了解 Oracle 在线重定义
Online Redefinition
by Maclean.liu
liu.maclean@gmail.com
www.oracledatabase12g.com
2. About Me
l Email:liu.maclean@gmail.com
l Blog:www.oracledatabase12g.com
l Oracle Certified Database Administrator Master 10g
and 11g
l Over 6 years experience with Oracle DBA technology
l Over 7 years experience with Linux technology
l Member Independent Oracle Users Group
l Member All China Oracle Users Group
l Presents for advanced Oracle topics: RAC,
DataGuard, Performance Tuning and Oracle Internal.
9. DBMS_REDEFINITION.START_REDEF_TABLE 过程的具体定义如下:
-- NAME: start_redef_table - start the online re-organization
-- INPUTS: uname - schema name
-- orig_table - name of table to be re-organized
-- int_table - name of interim table
-- col_mapping - select list col mapping
-- options_flag - flag indicating user options to use
-- orderby_cols - comma separated list of order by columns
-- followed by the optional ascending/descending
-- keyword
-- part_name - name of the partition to be redefined
PROCEDURE start_redef_table(uname IN VARCHAR2,
orig_table IN VARCHAR2,
int_table IN VARCHAR2,
col_mapping IN VARCHAR2 := NULL,
options_flag IN BINARY_INTEGER := 1,
orderby_cols IN VARCHAR2 := NULL,
part_name IN VARCHAR2 := NULL);
步骤 5: 使用 10g 以后出现的 COPY_TABLE_DEPENDENTS 存储过程在临时表上自动创建
如 constraints, triggers, indexes,privileges 类型的依赖对象(dependent object)。该
COPY_TABLE_DEPENDENTS 过程同时也会注册这些依赖对象。
使用 COPY_TABLE_DEPENDENTS 克隆依赖对象要比后面介绍
REGISTER_DEPENDENT_OBJECTS 过程来得简单方便。
该存储过程的 NUM_ERRORS(number of errors that occurred while cloning ddl)输出参数,显示
了其运行过程中所产生的错误数量。若 IGNORE_ERRORS(TRUE implies continue after errors,
FALSE otherwise)参数设置为 TRUE,那么该过程会忽略错误信息并不输出,继续其工作。
若设置为 FALSE,那么错误会在错误堆栈中显性输出。
10. DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS 过程的定义如下:
-- NAME: copy_table_dependents
--
-- INPUTS: uname - schema name
-- orig_table - name of table to be re-organized
-- int_table - name of interim table
-- copy_indexes - integer value indicating whether to
-- copy indexes
-- 0 - don't copy
-- 1 - copy using storage params/tablespace
-- of original index
-- copy_triggers - TRUE implies copy triggers, FALSE otherwise
-- copy_constraints - TRUE implies copy constraints, FALSE
-- otherwise
-- copy_privileges - TRUE implies copy priviliges, FALSE
-- otherwise
-- ignore errors - TRUE implies continue after errors, FALSE
-- otherwise
-- num_errors - number of errors that occurred while
-- cloning ddl
-- copy_statistics - TURE implies copy table statistics, FALSE
-- otherwise.
-- If copy_indexes is 1, copy index
-- related statistics, 0 otherwise.
PROCEDURE copy_table_dependents(uname IN VARCHAR2,
orig_table IN VARCHAR2,
int_table IN VARCHAR2,
copy_indexes IN PLS_INTEGER := 1,
copy_triggers IN BOOLEAN := TRUE,
copy_constraints IN BOOLEAN := TRUE,
copy_privileges IN BOOLEAN := TRUE,
ignore_errors IN BOOLEAN := FALSE,
num_errors OUT PLS_INTEGER,
copy_statistics IN BOOLEAN := FALSE);
我们可以通过查询 10g 以后出现的 DBA_REDEFINITION_ERRORS 视图
(DBA_REDEFINITION_ERRORS is an online redefinition view and displays the dependent
objects for which errors were raised while attempting to create similar objects on the interim table
of the redefinition.)来判断在使用 COPY_TABLE_DEPENDENTS 存储过程克隆依赖对象过程
中是否产生了错误。该视图记录了重定义过 程中在克隆依赖对象时产生的错误。 克隆对象
可能因缺少系统资源或原表的一个逻辑结构变化而失败。
12. DBMS_REDEFINITION.REGISTER_DEPENDENT_OBJECT 的详细定义如下:
-- NAME: register_dependent_object - register dependent object
--
-- INPUTS: uname - schema name
-- orig_table - name of table to be re-organized
-- int_table - name of interim table
-- dep_type - type of the dependent object
-- dep_owner - name of the dependent object owner
-- dep_orig_name- name of the dependent object defined on table
-- being re-organized
-- dep_int_name - name of the corressponding dependent object on
-- the interim table
PROCEDURE register_dependent_object(uname IN VARCHAR2,
orig_table IN VARCHAR2,
int_table IN VARCHAR2,
dep_type IN PLS_INTEGER,
dep_owner IN VARCHAR2,
dep_orig_name IN VARCHAR2,
dep_int_name IN VARCHAR2);
与 REGISTER_DEPENDENT_OBJECT 相反, unregister_dependent_object 过程用以注销依赖
对象(unregister dependent object)。
通过查询 10g 以后出现的 DBA_REDEFINITION_OBJECTS(an online redefinition view and
displays the objects involved in the current redefinitions.)可以确认是否所有需要的依赖的对象都
已被注册。该视图记录显示地被 REGISTER_DEPENDENT_OBJECT 注 册的或隐式地被
COPY_TABLE_DEPENDENTS 注册的依赖对象。注意该视图仅包含当前重定义的信息。
步骤 7:执行 DBMS_REDEFINITION.FINISH_REDEF_TABLE 存储过程完成表的在线重定
义。在此 procedure 运行过程中,原表会被以 Exclusive lock mode(TM lmode=6)排他模式锁住
极为短暂的一段时间(秒级),具体这段时间的长短受到原表上数据量的影响。 同时在此过程
中,会发生以下事件:
• 原表被真正意义上重定义,拥有临时表的所有属性、索引、约束、授权和触发器。
• 已注册的依赖对象会被自动重命名
• 临时表上的参考约束(referential constraint)会牵涉到重定义后的表上,且这些约束会被
自动启用。
13. 若重定义以 rowid 方式完成,那么重定义后的表上会出现一个隐藏字段叫做 M_ROW$$,我
们推荐将该隐藏字段设置为 unused:
ALTER TABLE table_name SET UNUSED (M_ROW$$)
DBMS_REDEFINITION.FINISH_REDEF_TABLE 过程的详细定义如下:
-- NAME: finish_redef_table - complete the online re-organization
-- INPUTS: uname - schema name
-- orig_table - name of table to be re-organized
-- int_table - name of interim table
-- part_name - name of the partition being redefined
PROCEDURE finish_redef_table(uname IN VARCHAR2,
orig_table IN VARCHAR2,
int_table IN VARCHAR2,
part_name IN VARCHAR2 := NULL);
以上我们了解了一个在线重定义的主要步骤,以及 10g 中引入的一些新的 procedure 和有用
视图,接下来我们实际操作一个在线重定义示范:
原表的定义和数据量如下:
create table SH.SALES
(
PROD_ID NUMBER not null,
CUST_ID NUMBER not null,
TIME_ID DATE not null,
CHANNEL_ID NUMBER not null,
PROMO_ID NUMBER not null,
QUANTITY_SOLD NUMBER(10,2) not null,
AMOUNT_SOLD NUMBER(10,2) not null
)
alter table SH.SALES
add constraint SALES_CHANNEL_FK foreign key (CHANNEL_ID)
references SH.CHANNELS (CHANNEL_ID);
alter table SH.SALES
add constraint SALES_CUSTOMER_FK foreign key (CUST_ID)
14. references SH.CUSTOMERS (CUST_ID);
alter table SH.SALES
add constraint SALES_PRODUCT_FK foreign key (PROD_ID)
references SH.PRODUCTS (PROD_ID);
alter table SH.SALES
add constraint SALES_PROMO_FK foreign key (PROMO_ID)
references SH.PROMOTIONS (PROMO_ID);
alter table SH.SALES
add constraint SALES_TIME_FK foreign key (TIME_ID)
references SH.TIMES (TIME_ID);
-- Create/Recreate indexes
create bitmap index SH.SALES_CHANNEL_BIX on SH.SALES (CHANNEL_ID);
create bitmap index SH.SALES_CUST_BIX on SH.SALES (CUST_ID);
create bitmap index SH.SALES_PROD_BIX on SH.SALES (PROD_ID);
create bitmap index SH.SALES_PROMO_BIX on SH.SALES (PROMO_ID);
create bitmap index SH.SALES_TIME_BIX on SH.SALES (TIME_ID);
SQL> select count(*) from sh.sales;
COUNT(*)
----------
918843
现在希望在原表的基础上增加默认为 188 的 number 类型 maclean 字段,且将该表转换为按照
range (TIME_ID)范围分区的分区表。
因为该表上有 7*24 的更新业务如下,所以只能使用在线重定义方式,且因为该表上没有
Primary key,所以只能使用 rowid 的重定义方式:
begin
loop
insert into sh.sales
values
(42, 938, to_date('1998-01-01', 'YYYY-MM-DD'), 2, 999, 1, 800);
insert into sh.sales
values
(42, 938, to_date('1998-01-01', 'YYYY-MM-DD'), 2, 999, 1, 800);
delete sh.sales where rownum = 1;
commit;
dbms_lock.sleep(0.5);
end loop;
end;
1. 利用 can_redef_table 存储过程验证原表是否可以以 rowid 方式重定义:
15. SQL> select * from v$version;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bi
PL/SQL Release 10.2.0.1.0 - Production
CORE 10.2.0.1.0 Production
TNS for Linux: Version 10.2.0.1.0 - Production
NLSRTL Version 10.2.0.1.0 - Production
SQL> select * from global_name;
GLOBAL_NAME
--------------------------------------------------------------------------------
www.oracledatabase12g.com & www.askmaclean.com
SQL> conn sh/sh
Connected.
SQL> begin
2 dbms_redefinition.can_redef_table(uname => 'SH',
3 tname => 'SALES',
4 options_flag =>
DBMS_REDEFINITION.CONS_USE_ROWID);
5 end;
6 /
begin
*
ERROR at line 1:
ORA-12091: cannot online redefine table "SH"."SALES" with materialized views
ORA-06512: at "SYS.DBMS_REDEFINITION", line 137
ORA-06512: at "SYS.DBMS_REDEFINITION", line 1478
ORA-06512: at line 2
发现 SALES 表上有物化视图,这回导致 online redefine 无法进行,找出物化视图并 drop 掉,
完成重定义后可以重建这些 materialized view:
SQL> select mview_name from dba_mviews where owner = 'SH';
MVIEW_NAME
------------------------------
FWEEK_PSCAT_SALES_MV
CAL_MONTH_SALES_MV
SQL> drop materialized view CAL_MONTH_SALES_MV;
Materialized view dropped.
SQL> drop materialized view FWEEK_PSCAT_SALES_MV;
Materialized view dropped.
SQL> begin
16. 2 dbms_redefinition.can_redef_table(uname => 'SH',
3 tname => 'SALES',
4 options_flag =>
DBMS_REDEFINITION.CONS_USE_ROWID);
5 end;
6 /
PL/SQL procedure successfully completed.
再次验证成功。
2. 创建空的临时表,在原表的基础上加入 MACLEAN 字段以及分区定义:
create table SH.INT_SALES
(
PROD_ID NUMBER not null,
CUST_ID NUMBER not null,
TIME_ID DATE not null,
CHANNEL_ID NUMBER not null,
PROMO_ID NUMBER not null,
QUANTITY_SOLD NUMBER(10,2) not null,
AMOUNT_SOLD NUMBER(10,2) not null,
MACLEAN NUMBER(10,2) default 188 not null
)
partition by range (TIME_ID)
(
partition SALES_1995 values less than (TO_DATE(' 1996-01-01 00:00:00', 'SYYYY-
MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
tablespace EXAMPLE
pctfree 0
initrans 1
maxtrans 255,
partition SALES_1996 values less than (TO_DATE(' 1997-01-01 00:00:00', 'SYYYY-
MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
tablespace EXAMPLE
pctfree 0
initrans 1
maxtrans 255,
partition SALES_H1_1997 values less than (TO_DATE(' 1997-07-01 00:00:00',
'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
tablespace EXAMPLE
pctfree 0
initrans 1
maxtrans 255,
...................................
17. 建表 DDL 过长,以上节选主要部分
并在会话级别启用 FORCE PARALLEL:
alter session force parallel dml parallel 4;
alter session force parallel query parallel 4;
3.调用 DBMS_REDEFINITION.START_REDEF_TABLE 存储过程启动重定义进程
SQL> set timing on;
begin
DBMS_REDEFINITION.START_REDEF_TABLE(uname => 'SH',
orig_table => 'SALES',
int_table => 'INT_SALES',
col_mapping => 'PROD_ID PROD_ID,CUST_ID CUST_ID,TIME_ID
TIME_ID,CHANNEL_ID CHANNEL_ID,PROMO_ID PROMO_ID,QUANTITY_SOLD
QUANTITY_SOLD,AMOUNT_SOLD AMOUNT_SOLD',
options_flag => DBMS_REDEFINITION.CONS_USE_ROWID);
end;
PL/SQL procedure successfully completed.
Elapsed: 00:00:04.23
SQL> select count(*) from int_sales;
COUNT(*)
----------
921539
Elapsed: 00:00:00.23
18. 4. 调用 COPY_TABLE_DEPENDENTS 过程克隆依赖对象:
SQL> DECLARE
2 num_errors PLS_INTEGER;
3 BEGIN
4 DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(uname => 'SH',
5 orig_table => 'SALES',
6 int_table => 'INT_SALES',
7 copy_indexes =>
DBMS_REDEFINITION.cons_orig_params,
8 copy_triggers => TRUE,
9 copy_constraints => FALSE,
10 copy_privileges => TRUE,
11 ignore_errors => FALSE,
12 num_errors => num_errors,
13 copy_statistics => TRUE);
14 END;
15 /
DECLARE
*
ERROR at line 1:
ORA-25122: Only LOCAL bitmap indexes are permitted on partitioned tables
ORA-06512: at "SYS.DBMS_REDEFINITION", line 1173
ORA-06512: at "SYS.DBMS_REDEFINITION", line 1712
ORA-06512: at line 4
Elapsed: 00:00:00.06
SQL> select * from DBA_REDEFINITION_ERRORS;
OBJECT_TYP OBJECT_OWNER OBJECT_NAME
---------- ------------------------------ ------------------------------
BASE_TABLE_OWNER BASE_TABLE_NAME
------------------------------ ------------------------------
DDL_TXT
--------------------------------------------------------------------------------
INDEX SH SALES_CHANNEL_BIX
SH SALES
CREATE BITMAP INDEX "SH"."TMP$$_SALES_CHANNEL_BIX0" ON "SH"."INT_SALES" ("CHANNE
因为原表上有 bitmap indexes,而目标的 partitioned tables(分区表)仅支持 LOCAL bitmap
indexes, 这里可以通过 REGISTER_DEPENDENT_OBJECT 来注册 LOCAL bitmap indexes 依
20. PL/SQL procedure successfully completed.
Elapsed: 00:00:00.87
SQL> select count(*) from int_sales;
COUNT(*)
----------
923135
6.执行 finish_redef_table 过程完成重定义:
begin
dbms_redefinition.finish_redef_table(uname => 'SH',
orig_table => 'SALES',
int_table => 'INT_SALES');
end;
/
SQL> desc sales;
Name Null? Type
----------------------------------------- -------- ----------------------------
PROD_ID NOT NULL NUMBER
CUST_ID NOT NULL NUMBER
TIME_ID NOT NULL DATE
CHANNEL_ID NOT NULL NUMBER
PROMO_ID NOT NULL NUMBER
QUANTITY_SOLD NOT NULL NUMBER(10,2)
AMOUNT_SOLD NOT NULL NUMBER(10,2)
MACLEAN NOT NULL NUMBER(10,2)
SQL> select count(*) from sales partition (SALES_Q2_2000);
COUNT(*)
----------
55515
Elapsed: 00:00:00.02
SQL> select distinct maclean from sales;
MACLEAN
----------
188
Elapsed: 00:00:00.32
21. 以上成功完成了对 SALES 表的 Online Redefinition,由非分区表在线重定义为分区表且增加
了一个字段。
这里因为我们使用 rowid 方式,所以重定义完的表上会多出一个隐藏字段, 从 10.2 开始
M_ROW$$的隐藏列会被命名为 SYS_%DATE%的形式,且默认即为 unused 状态:
SQL> set linesize 90 pagesize 1400
SQL> select *
2 from dba_tab_cols
3 where owner = 'SH'
4 and column_name like 'SYS%'
5 and table_name='SALES';
OWNER TABLE_NAME
------------------------------ ------------------------------
COLUMN_NAME
------------------------------
DATA_TYPE
--------------------------------------------------------------------------------
----------
DAT DATA_TYPE_OWNER DATA_LENGTH DATA_PRECISION DATA_SCALE N
COLUMN_ID
--- ------------------------------ ----------- -------------- ---------- -
----------
DEFAULT_LENGTH
--------------
DATA_DEFAULT
--------------------------------------------------------------------------------
NUM_DISTINCT LOW_VALUE
------------ ----------------------------------------------------------------
HIGH_VALUE DENSITY
NUM_NULLS
---------------------------------------------------------------- ----------
----------
NUM_BUCKETS LAST_ANAL SAMPLE_SIZE CHARACTER_SET_NAME
----------- --------- ----------- --------------------------------------------
CHAR_COL_DECL_LENGTH GLO USE AVG_COL_LEN CHAR_LENGTH C V80 DAT HID VIR
SEGMENT_COLUMN_ID
-------------------- --- --- ----------- ----------- - --- --- --- ---
-----------------
INTERNAL_COLUMN_ID HISTOGRAM
------------------ ---------------
QUALIFIED_COL_NAME
--------------------------------------------------------------------------------
----------
SH SALES
SYS_C00009_11120703:40:57$
VARCHAR2
255 Y
22. CHAR_CS
255 NO NO 255 B NO YES YES NO 9
9 NONE
SYS_C00009_11120703:40:57$
================================================================================
==========
SQL> select * from dba_unused_col_tabs ;
OWNER TABLE_NAME COUNT
------------------------------ ------------------------------ ----------
SH SALES 1
SQL> alter table sales drop unused columns;
Table altered.
Elapsed: 00:00:13.36
SQL> select * from dba_unused_col_tabs ;
no rows selected
23. 若在完成重定义(执行 finish_redef_table)之前希望中断在线重定义表,则需要使用
DBMS_REDEFINITION.ABORT_REDEF_TABLE 明确手动中断 abort,如:
begin
dbms_redefinition.abort_redef_table(uname => 'SH',
orig_table => 'SALES',
int_table => 'INT_SALES');
end;
/
该 abort_redef_table 过程的详细定义如下:
-- NAME: abort_redef_table - clean up after errors or abort the
-- online re-organization
-- INPUTS: uname - schema name
-- orig_table - name of table to be re-organized
-- int_table - name of interim table
-- part_name - name of the partition being redefined
PROCEDURE abort_redef_table(uname IN VARCHAR2,
orig_table IN VARCHAR2,
int_table IN VARCHAR2,
part_name IN VARCHAR2 := NULL);