SlideShare a Scribd company logo
了解 Oracle 在线重定义
 Online Redefinition




      by Maclean.liu
            liu.maclean@gmail.com
        www.oracledatabase12g.com
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.
How To Find Maclean Liu?
Online Redefinition 在线重定义对象是 Oracle 中很酷的一种特性,它可以帮助我们在 7*24 在
线的系统中从容地做出数据对象的在线定义修改,是 Oracle 数据库保证其高可用性的重要技
术。




在线重定义 Online Redefinition 特性在许多场景中都是十分有用的,例如:

  •   修改表的 Storage 存储参数
  •   在同一 Schema 下将表移动到不同的表空间
  •   转换非分区表为分区表
  •   添加或删除分区
  •   重新创建表以减少碎片,降低高水位
  •   将堆组织的表改变为索引组织表
  •   添加或删除列
使用 Online Redefinition 在线重定义需要用到 DBMS_REDEFINITION 程序
包,EXECUTE_CATALOG_ROLE 角色默认被赋予该 PL/SQL Package 的执行权限。除了执
行该程序包的权限外,用户还需要拥有以下权限:

  •     CREATE ANY TABLE
  •     ALTER ANY TABLE
  •     DROP ANY TABLE
  •     LOCK ANY TABLE
  •     SELECT ANY TABLE



若要执行 COPY_TABLE_DEPENDENTS 存储过程则还需要以下权限:

  •     CREATE ANY TRIGGER
  •     CREATE ANY INDEX




在早期版本中在线重定义(Online Redefinition)对于某些具有特殊数据类型的表存在诸多限
制,从 Oracle 10g 开始拥有以下数据类型的表也支持在线重定义(Online Redefinition)了:



  1. 存在 LONG 类型 column 字段的表可以被在线重定义(redefined online);但是 LONG 类
      型字段只能被转换为 character large object 即 CLOB
  2. 存在 LONG RAW 类型 column 字段的表可以被在线重定义(redefined online);但是
      LONG RAW 类型字段只能被转换为 binary large object 即 BLOB



此外从 10g 开始支持对 replication table 的在线重定义:

  1. 包含在 master-master replications 中的表
  2. 在 n-way master 复制环境中没有 horizontal 或 vertical subsetting,或者允许 column
      transformations 的表



我们可以通过以下步骤一步一步地完成对一张普通堆表的在线重定义(Online Redefinition):
步骤 1:决定我们所要使用的重定义方式(redefinition method),存在 2 种方式:



   • 第一种是我们较为推荐的方式,采用 Primary Key 主键或者 pseudoprimary key 伪主键
     实施重定义(从 Oracle 10g 开始支持 pseudoprimary key 伪主键)。 这里 pseudoprimary
     key 伪主键要求是唯一键且所有的成员列均是非空 NOT NULL。使用该种方式,重定
     义前和重定义后版本的表均必须有相同的 Primary Key 主键或者 pseudoprimary key 伪
     主键列。不管是从性能角度,还是从操作的复杂度考虑,常规场景中都推荐尽可能使
     用此种方式
   • 第二种方式是使用 rowid 进行 redefinition。首先索引组织表 index-organized table (IOT)
     不支持使用 rowid 的重定义方式。此外,若使用该种 redefinition 方式,最终会有一个
     隐藏的字段 M_ROW$$被加入到重定义后版 本的表上,Oracle 官方推荐在重定义完成
     后将该 M_ROW$$字段 drop 掉或者标记为 unused。



步骤 2:通过调用 DBMS_REDEFINITION.CAN_REDEF_TABLE 存储过程并以
OPTIONS_FLAG(flag indicating user options to use)参数指定所要使用的重定义方式,来验证
原表是否可以以这样的方式来在线重定义。若原表不符合指定重定义方式的要求,那么该过
程会报出一个错误,说 明该表不能在线重定义的具体原因。

若指定 OPTIONS_FLAG 为常数 DBMS_REDEFINITION.CONS_USE_PK(cons_use_pk
CONSTANT PLS_INTEGER := 1;),意为使用 primary keys 或 pseudoprimary keys 的重定义方
式。

若指定 OPTIONS_FLAG 为常数
DBMS_REDEFINITION.CONS_USE_ROWID(cons_use_rowid CONSTANT PLS_INTEGER :=
2;),意为使用 rowid 的重定义方式。

DBMS_REDEFINITION.CAN_REDEF_TABLE 过程的详细定义如下:


-- NAME:     can_redef_table - check if given table can be re-defined
-- INPUTS:   uname        - table owner name
--           tname        - table name
--           options_flag - flag indicating user options to use
--           part_name    - partition name
PROCEDURE can_redef_table(uname        IN VARCHAR2,
             tname        IN VARCHAR2,
             options_flag IN PLS_INTEGER := 1,
             part_name    IN VARCHAR2 := NULL);
步骤 3:在原表的同一 Schema 下创建一张空的临时表(interim table), 该表具有所有我们想
要的属性。若有 column 字段需要通过重定义 drop 掉,那么就在这张临时表的定义中去掉该
column。同理若有 column 字段 需要通过重定义加入到表上,那么就在临时表上加入该
column 的定义。

理论上我们可以并行地实施表的在线重定义;若已经同时指定了原表和临时表的并发度,那
么也请确保实施操作的本会话(session)已经启用了会话 级别的并行执行, 这样 Oracle 服务
进程会在实施重定义的过程中尽可能地使用并行执行( parallel execution )。




可以采用以下 ALTER SESSION 命令启用并行的 DML 和查询:


alter session force parallel dml parallel 4;
alter session force parallel query parallel 4;




如原表的结构为 HR.JOBS:


SQL> desc hr.jobs;
 Name                                        Null?      Type
 -----------------------------------------   --------   ----------------------------
 JOB_ID                                      NOT NULL   VARCHAR2(10)
 JOB_TITLE                                   NOT NULL   VARCHAR2(35)
 MIN_SALARY                                             NUMBER(8)
 MAX_SALARY                                             NUMBER(8)
 EXEMPT_STATUS                                          VARCHAR2(3)
希望在此原表结构基础上加入默认为 188 的 Number 类型名为 Maclean 的字段 column,那么
我们创建临时表如下:


SQL> create table    hr.jobs_hist_int
 2   ( job_id varchar2(10) primary key,
 3     job_title varchar2(35) NOT NULL,
 4     min_salary number(8),
 5     max_salary number(8),
 6     exempt_status varchar2(3),
 7     maclean number(8) default 188);

Table created.




步骤 4: 调用 DBMS_REDEFINITION.START_REDEF_TABLE 存储过程启动重定义进程,
使用该过程需要指定以下的参数:

   1. 将要重定义的表名
   2. 临时表的名字(interim table name)
   3. 字段的映射信息(column mapping)
   4. 重定义使用的方式(primary key or rowid)
   5. 此外还可以指定用以排序的字段



若字段映射参数 column mapping 未指定,那么 Oracle 假设所有原表上的列(字段名不变)都被
包含在中间表上了。 若指定了 column mapping 信息,那么只有那些在字段映射中明确指定
的原表字段被考虑重定义。若没有指定使用何种重定义方式,那么 Oracle 默认会采用
primary keys 或 pseudoprimary keys 的方式。

从 10g 开始出现了 ORDERBY_COLS 参数可以用于指定在临时表初始化过程中数据行按照字
段排序。
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,那么错误会在错误堆栈中显性输出。
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 存储过程克隆依赖对象过程
中是否产生了错误。该视图记录了重定义过 程中在克隆依赖对象时产生的错误。 克隆对象
可能因缺少系统资源或原表的一个逻辑结构变化而失败。
在我们成功克隆这些依赖对象后,相关错误将会从该视图中被移除。 我们可以反复执行
COPY_TABLE_DEPENDENTS 或后面介绍的 REGISTER_DEPENDENT_OBJECTS 过程尝试
重新克隆依赖对象。



示例错误如下:


SQL> select * from DBA_REDEFINITION_ERRORS;

OBJECT_TYP OBJECT_OWNER                   OBJECT_NAME
---------- ------------------------------ ------------------------------
BASE_TABLE_OWNER               BASE_TABLE_NAME
------------------------------ ------------------------------
DDL_TXT
--------------------------------------------------------------------------------
INDEX      HR                             JOB_ID_PK
HR                             JOBS
CREATE UNIQUE INDEX "HR"."TMP$$_JOB_ID_PK0" ON "HR"."INT_JOBS_HIST" ("JOB_ID")




步骤 6: 这不是必需的步骤。我们也可以使用 10g 以后出现的
REGISTER_DEPENDENT_OBJECT 将正要重定义的表上 的依赖对象注册到临时表上对应的
依赖对象。 换句话说 COPY_TABLE_DEPENDENTS 的功
能,REGISTER_DEPENDENT_OBJECT 也是可以做到的,但是没有
COPY_TABLE_DEPENDENTS 来得简单方便。若我们想在原表的基础上建立额外的依赖对
象,那么也可以用该过程来手动建立。若之前的 COPY_TABLE_DEPENDENTS 运行失败
了,那么也可以通过 REGISTER_DEPENDENT_OBJECT 来手工补救,注册那些没有克 隆成
功的依赖对象。

注意 REGISTER_DEPENDENT_OBJECT 过程也是 10g 以后出现的,在早期版本中我们是要
手动重命名依赖对象的。
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)会牵涉到重定义后的表上,且这些约束会被
      自动启用。
若重定义以 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)
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 方式重定义:
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
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,
...................................
建表 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
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 依
赖对象,作为教学示例我们不这样做,而选择不克隆索引类型的依赖对象,指定
copy_indexes 参数为 0:


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       =>    0,
 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 /

PL/SQL procedure successfully completed.

Elapsed: 00:00:03.03




5. 利用 sync_interim_table 过程同步临时表的数据减少 finish_redef_table 的耗时:


SQL> select count(*) from sales;

 COUNT(*)
----------
  923046

Elapsed: 00:00:00.01

SQL> select count(*) from int_sales;

 COUNT(*)
----------
  921539

Elapsed: 00:00:00.24

SQL> begin
 2    dbms_redefinition.sync_redef_table(uname      => 'SH',
 3                                         orig_table => 'SALES',
 4                                         int_table => 'INT_SALES');
 5 end;
 6 /
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
以上成功完成了对 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
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
若在完成重定义(执行 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);
© 2011, www.oracledatabase12g.com. 版权所有.文章允许转载,但必须以链接方式注明源地址,
否则追究法律责任.


相关文章 | Related Posts:
   1. How to check and disable Adaptive Cursor Sharing in 11g
   2. How to Re-Organize a Table Online
   3. 解决 ORA-14098 分区交换索引不匹配错误
   4. Oracle SQL Developer 的一个 Bug
   5. 滚动游标失效(Rolling Cursor Invalidations)
   6. SCRIPT: VALIDATE.SQL to ANALYZE .. VALIDATE STRUCTURE objects in a
      Tablespace
   7. SQL PLAN MANAGEMENT
   8. How to find error message from OMS repository

More Related Content

PDF
Oracle试题Exam Adminv1.1
PDF
11g新特性streams同步捕获
PDF
配置Oracle 10g 双向流复制
PPT
Essential oracle security internal for dba
PDF
A.oracle 查询结果的缓存问题
PDF
Sql语句大全大全(经典珍藏版)
PPTX
4, workflow tables & api
DOCX
Mnesia用户手册
Oracle试题Exam Adminv1.1
11g新特性streams同步捕获
配置Oracle 10g 双向流复制
Essential oracle security internal for dba
A.oracle 查询结果的缓存问题
Sql语句大全大全(经典珍藏版)
4, workflow tables & api
Mnesia用户手册

What's hot (20)

PDF
Oracle Tablespace介紹
PDF
A.oracle 数据字典与脚本初步
DOC
Jdbc4 0 规范技术预研
PDF
Oracle 資料庫檔案介紹
PDF
Oracle 資料庫建立
PPTX
10, OCP - flashback
PPT
Hibernate 映射配置文件详解
DOC
Spring入门纲要
PPTX
PostgreSQL 10 New Features
PPTX
3, OCP - instance management
PDF
Oracle SGA 介紹
PDF
【 I Love Joomla 】- Joomla!佈景製作教學
PDF
Row Set初步学习V1.1
PDF
【Ask maclean技术分享】oracle dba技能列表 z
DOC
J2ee面试知识
DOC
Cassandra的初步使用及一些简单的操作
PPTX
I Love Joomla! 佈景製作教學 0212
PDF
Oracle使用者安全設定
PPT
MySQL源码分析.01.代码结构与基本流程
PPT
Ch08
Oracle Tablespace介紹
A.oracle 数据字典与脚本初步
Jdbc4 0 规范技术预研
Oracle 資料庫檔案介紹
Oracle 資料庫建立
10, OCP - flashback
Hibernate 映射配置文件详解
Spring入门纲要
PostgreSQL 10 New Features
3, OCP - instance management
Oracle SGA 介紹
【 I Love Joomla 】- Joomla!佈景製作教學
Row Set初步学习V1.1
【Ask maclean技术分享】oracle dba技能列表 z
J2ee面试知识
Cassandra的初步使用及一些简单的操作
I Love Joomla! 佈景製作教學 0212
Oracle使用者安全設定
MySQL源码分析.01.代码结构与基本流程
Ch08
Ad

Viewers also liked (20)

DOC
Comparison table jan lokpal bill govt lokpal bill and ncpri drafts
DOC
خطة التدريس السنوية اللغة العربية11 thn 3 2013 rpt
PDF
Miten toteutan informaation visualisoinnin?
DOC
Untitled 1
PPTX
Rwd (uk grime magazine)
PPTX
Afternoon
PPT
N.h. mountains final
PDF
11g r2新特性之standby max_data_delay
PPTX
Relational Capital and Social Capital: One or two Fields of Research?
PPT
Skills & Habits Energy Field
PDF
Vortex Mobile @ Facebook Developer Garage Toronto
PPT
An introduction-for-authors
PDF
Villaggio - November at a Glance Email
DOCX
Puntuaciones provisionales (martes 25 a las 12h)
PPT
14812 learning
PPTX
Ci 102 assignment power point
PPTX
New Zealand Franchising Confidence Index | January 2013
PDF
【Maclean liu技术分享】深入理解oracle中mutex的内部原理
PPTX
Apouc 4min pitch_biotwang_v2
PDF
Risk communication with the media anastas
Comparison table jan lokpal bill govt lokpal bill and ncpri drafts
خطة التدريس السنوية اللغة العربية11 thn 3 2013 rpt
Miten toteutan informaation visualisoinnin?
Untitled 1
Rwd (uk grime magazine)
Afternoon
N.h. mountains final
11g r2新特性之standby max_data_delay
Relational Capital and Social Capital: One or two Fields of Research?
Skills & Habits Energy Field
Vortex Mobile @ Facebook Developer Garage Toronto
An introduction-for-authors
Villaggio - November at a Glance Email
Puntuaciones provisionales (martes 25 a las 12h)
14812 learning
Ci 102 assignment power point
New Zealand Franchising Confidence Index | January 2013
【Maclean liu技术分享】深入理解oracle中mutex的内部原理
Apouc 4min pitch_biotwang_v2
Risk communication with the media anastas
Ad

Similar to 了解Oracle在线重定义online redefinition (20)

PDF
Oracle中比对2张表之间数据是否一致的几种方法
PDF
Mysql开发与优化
PDF
网易分布式数据库平台
PPT
Sql Server 高级技巧系列之二:重编译详解
PPT
Oracle11g database sql语言基础
PDF
Oracle 高可用概述
PDF
Oracle ha
PPT
Oracle公司内部数据库培训资料
PPT
企业常用Sql
PDF
Oracle的Constraint约束V1.1
PPT
Oracle数据库分析函数详解
PDF
oracle优化器星型转换
PPT
第6章 数据查询
PDF
Csdn Emag(Oracle)第二期
PDF
MySQL_EXPLAIN_liling
PPT
Oracle经典教程
PDF
PPT
Oracle的闪回特性
PPT
Something about oracle joins
PDF
MySQL数据库生产环境维护
Oracle中比对2张表之间数据是否一致的几种方法
Mysql开发与优化
网易分布式数据库平台
Sql Server 高级技巧系列之二:重编译详解
Oracle11g database sql语言基础
Oracle 高可用概述
Oracle ha
Oracle公司内部数据库培训资料
企业常用Sql
Oracle的Constraint约束V1.1
Oracle数据库分析函数详解
oracle优化器星型转换
第6章 数据查询
Csdn Emag(Oracle)第二期
MySQL_EXPLAIN_liling
Oracle经典教程
Oracle的闪回特性
Something about oracle joins
MySQL数据库生产环境维护

More from maclean liu (20)

PDF
Mysql企业备份发展及实践
PDF
Oracle専用データ復旧ソフトウェアprm dulユーザーズ・マニュアル
PDF
【诗檀软件 郭兆伟-技术报告】跨国企业级Oracle数据库备份策略
PDF
基于Oracle 12c data guard & far sync的低资源消耗两地三数据中心容灾方案
PDF
TomCat迁移步骤简述以及案例
PDF
PRM DUL Oracle Database Health Check
PDF
dbdao.com 汪伟华 my-sql-replication复制高可用配置方案
DOCX
Vbox virtual box在oracle linux 5 - shoug 梁洪响
PDF
【诗檀软件】Mysql高可用方案
PPTX
Shoug at apouc2015 4min pitch_biotwang_v2
PDF
使用Oracle osw analyzer工具分析oswbb日志,并绘制系统性能走势图1
PDF
诗檀软件 Oracle开发优化基础
PDF
Orclrecove 1 pd-prm-dul testing for oracle database recovery_20141030_biot_wang
PDF
诗檀软件 – Oracle数据库修复专家 oracle数据块损坏知识2014-10-24
PDF
追求Jdbc on oracle最佳性能?如何才好?
PDF
使用Virtual box在oracle linux 5.7上安装oracle database 11g release 2 rac的最佳实践
PDF
Prm dul is an oracle database recovery tool database
PDF
Oracle prm dul, jvm and os
PDF
Oracle dba必备技能 使用os watcher工具监控系统性能负载
PDF
Parnassus data recovery manager for oracle database user guide v0.3
Mysql企业备份发展及实践
Oracle専用データ復旧ソフトウェアprm dulユーザーズ・マニュアル
【诗檀软件 郭兆伟-技术报告】跨国企业级Oracle数据库备份策略
基于Oracle 12c data guard & far sync的低资源消耗两地三数据中心容灾方案
TomCat迁移步骤简述以及案例
PRM DUL Oracle Database Health Check
dbdao.com 汪伟华 my-sql-replication复制高可用配置方案
Vbox virtual box在oracle linux 5 - shoug 梁洪响
【诗檀软件】Mysql高可用方案
Shoug at apouc2015 4min pitch_biotwang_v2
使用Oracle osw analyzer工具分析oswbb日志,并绘制系统性能走势图1
诗檀软件 Oracle开发优化基础
Orclrecove 1 pd-prm-dul testing for oracle database recovery_20141030_biot_wang
诗檀软件 – Oracle数据库修复专家 oracle数据块损坏知识2014-10-24
追求Jdbc on oracle最佳性能?如何才好?
使用Virtual box在oracle linux 5.7上安装oracle database 11g release 2 rac的最佳实践
Prm dul is an oracle database recovery tool database
Oracle prm dul, jvm and os
Oracle dba必备技能 使用os watcher工具监控系统性能负载
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.
  • 3. How To Find Maclean Liu?
  • 4. Online Redefinition 在线重定义对象是 Oracle 中很酷的一种特性,它可以帮助我们在 7*24 在 线的系统中从容地做出数据对象的在线定义修改,是 Oracle 数据库保证其高可用性的重要技 术。 在线重定义 Online Redefinition 特性在许多场景中都是十分有用的,例如: • 修改表的 Storage 存储参数 • 在同一 Schema 下将表移动到不同的表空间 • 转换非分区表为分区表 • 添加或删除分区 • 重新创建表以减少碎片,降低高水位 • 将堆组织的表改变为索引组织表 • 添加或删除列
  • 5. 使用 Online Redefinition 在线重定义需要用到 DBMS_REDEFINITION 程序 包,EXECUTE_CATALOG_ROLE 角色默认被赋予该 PL/SQL Package 的执行权限。除了执 行该程序包的权限外,用户还需要拥有以下权限: • CREATE ANY TABLE • ALTER ANY TABLE • DROP ANY TABLE • LOCK ANY TABLE • SELECT ANY TABLE 若要执行 COPY_TABLE_DEPENDENTS 存储过程则还需要以下权限: • CREATE ANY TRIGGER • CREATE ANY INDEX 在早期版本中在线重定义(Online Redefinition)对于某些具有特殊数据类型的表存在诸多限 制,从 Oracle 10g 开始拥有以下数据类型的表也支持在线重定义(Online Redefinition)了: 1. 存在 LONG 类型 column 字段的表可以被在线重定义(redefined online);但是 LONG 类 型字段只能被转换为 character large object 即 CLOB 2. 存在 LONG RAW 类型 column 字段的表可以被在线重定义(redefined online);但是 LONG RAW 类型字段只能被转换为 binary large object 即 BLOB 此外从 10g 开始支持对 replication table 的在线重定义: 1. 包含在 master-master replications 中的表 2. 在 n-way master 复制环境中没有 horizontal 或 vertical subsetting,或者允许 column transformations 的表 我们可以通过以下步骤一步一步地完成对一张普通堆表的在线重定义(Online Redefinition):
  • 6. 步骤 1:决定我们所要使用的重定义方式(redefinition method),存在 2 种方式: • 第一种是我们较为推荐的方式,采用 Primary Key 主键或者 pseudoprimary key 伪主键 实施重定义(从 Oracle 10g 开始支持 pseudoprimary key 伪主键)。 这里 pseudoprimary key 伪主键要求是唯一键且所有的成员列均是非空 NOT NULL。使用该种方式,重定 义前和重定义后版本的表均必须有相同的 Primary Key 主键或者 pseudoprimary key 伪 主键列。不管是从性能角度,还是从操作的复杂度考虑,常规场景中都推荐尽可能使 用此种方式 • 第二种方式是使用 rowid 进行 redefinition。首先索引组织表 index-organized table (IOT) 不支持使用 rowid 的重定义方式。此外,若使用该种 redefinition 方式,最终会有一个 隐藏的字段 M_ROW$$被加入到重定义后版 本的表上,Oracle 官方推荐在重定义完成 后将该 M_ROW$$字段 drop 掉或者标记为 unused。 步骤 2:通过调用 DBMS_REDEFINITION.CAN_REDEF_TABLE 存储过程并以 OPTIONS_FLAG(flag indicating user options to use)参数指定所要使用的重定义方式,来验证 原表是否可以以这样的方式来在线重定义。若原表不符合指定重定义方式的要求,那么该过 程会报出一个错误,说 明该表不能在线重定义的具体原因。 若指定 OPTIONS_FLAG 为常数 DBMS_REDEFINITION.CONS_USE_PK(cons_use_pk CONSTANT PLS_INTEGER := 1;),意为使用 primary keys 或 pseudoprimary keys 的重定义方 式。 若指定 OPTIONS_FLAG 为常数 DBMS_REDEFINITION.CONS_USE_ROWID(cons_use_rowid CONSTANT PLS_INTEGER := 2;),意为使用 rowid 的重定义方式。 DBMS_REDEFINITION.CAN_REDEF_TABLE 过程的详细定义如下: -- NAME: can_redef_table - check if given table can be re-defined -- INPUTS: uname - table owner name -- tname - table name -- options_flag - flag indicating user options to use -- part_name - partition name PROCEDURE can_redef_table(uname IN VARCHAR2, tname IN VARCHAR2, options_flag IN PLS_INTEGER := 1, part_name IN VARCHAR2 := NULL);
  • 7. 步骤 3:在原表的同一 Schema 下创建一张空的临时表(interim table), 该表具有所有我们想 要的属性。若有 column 字段需要通过重定义 drop 掉,那么就在这张临时表的定义中去掉该 column。同理若有 column 字段 需要通过重定义加入到表上,那么就在临时表上加入该 column 的定义。 理论上我们可以并行地实施表的在线重定义;若已经同时指定了原表和临时表的并发度,那 么也请确保实施操作的本会话(session)已经启用了会话 级别的并行执行, 这样 Oracle 服务 进程会在实施重定义的过程中尽可能地使用并行执行( parallel execution )。 可以采用以下 ALTER SESSION 命令启用并行的 DML 和查询: alter session force parallel dml parallel 4; alter session force parallel query parallel 4; 如原表的结构为 HR.JOBS: SQL> desc hr.jobs; Name Null? Type ----------------------------------------- -------- ---------------------------- JOB_ID NOT NULL VARCHAR2(10) JOB_TITLE NOT NULL VARCHAR2(35) MIN_SALARY NUMBER(8) MAX_SALARY NUMBER(8) EXEMPT_STATUS VARCHAR2(3)
  • 8. 希望在此原表结构基础上加入默认为 188 的 Number 类型名为 Maclean 的字段 column,那么 我们创建临时表如下: SQL> create table hr.jobs_hist_int 2 ( job_id varchar2(10) primary key, 3 job_title varchar2(35) NOT NULL, 4 min_salary number(8), 5 max_salary number(8), 6 exempt_status varchar2(3), 7 maclean number(8) default 188); Table created. 步骤 4: 调用 DBMS_REDEFINITION.START_REDEF_TABLE 存储过程启动重定义进程, 使用该过程需要指定以下的参数: 1. 将要重定义的表名 2. 临时表的名字(interim table name) 3. 字段的映射信息(column mapping) 4. 重定义使用的方式(primary key or rowid) 5. 此外还可以指定用以排序的字段 若字段映射参数 column mapping 未指定,那么 Oracle 假设所有原表上的列(字段名不变)都被 包含在中间表上了。 若指定了 column mapping 信息,那么只有那些在字段映射中明确指定 的原表字段被考虑重定义。若没有指定使用何种重定义方式,那么 Oracle 默认会采用 primary keys 或 pseudoprimary keys 的方式。 从 10g 开始出现了 ORDERBY_COLS 参数可以用于指定在临时表初始化过程中数据行按照字 段排序。
  • 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 存储过程克隆依赖对象过程 中是否产生了错误。该视图记录了重定义过 程中在克隆依赖对象时产生的错误。 克隆对象 可能因缺少系统资源或原表的一个逻辑结构变化而失败。
  • 11. 在我们成功克隆这些依赖对象后,相关错误将会从该视图中被移除。 我们可以反复执行 COPY_TABLE_DEPENDENTS 或后面介绍的 REGISTER_DEPENDENT_OBJECTS 过程尝试 重新克隆依赖对象。 示例错误如下: SQL> select * from DBA_REDEFINITION_ERRORS; OBJECT_TYP OBJECT_OWNER OBJECT_NAME ---------- ------------------------------ ------------------------------ BASE_TABLE_OWNER BASE_TABLE_NAME ------------------------------ ------------------------------ DDL_TXT -------------------------------------------------------------------------------- INDEX HR JOB_ID_PK HR JOBS CREATE UNIQUE INDEX "HR"."TMP$$_JOB_ID_PK0" ON "HR"."INT_JOBS_HIST" ("JOB_ID") 步骤 6: 这不是必需的步骤。我们也可以使用 10g 以后出现的 REGISTER_DEPENDENT_OBJECT 将正要重定义的表上 的依赖对象注册到临时表上对应的 依赖对象。 换句话说 COPY_TABLE_DEPENDENTS 的功 能,REGISTER_DEPENDENT_OBJECT 也是可以做到的,但是没有 COPY_TABLE_DEPENDENTS 来得简单方便。若我们想在原表的基础上建立额外的依赖对 象,那么也可以用该过程来手动建立。若之前的 COPY_TABLE_DEPENDENTS 运行失败 了,那么也可以通过 REGISTER_DEPENDENT_OBJECT 来手工补救,注册那些没有克 隆成 功的依赖对象。 注意 REGISTER_DEPENDENT_OBJECT 过程也是 10g 以后出现的,在早期版本中我们是要 手动重命名依赖对象的。
  • 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 依
  • 19. 赖对象,作为教学示例我们不这样做,而选择不克隆索引类型的依赖对象,指定 copy_indexes 参数为 0: 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 => 0, 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 / PL/SQL procedure successfully completed. Elapsed: 00:00:03.03 5. 利用 sync_interim_table 过程同步临时表的数据减少 finish_redef_table 的耗时: SQL> select count(*) from sales; COUNT(*) ---------- 923046 Elapsed: 00:00:00.01 SQL> select count(*) from int_sales; COUNT(*) ---------- 921539 Elapsed: 00:00:00.24 SQL> begin 2 dbms_redefinition.sync_redef_table(uname => 'SH', 3 orig_table => 'SALES', 4 int_table => 'INT_SALES'); 5 end; 6 /
  • 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);
  • 24. © 2011, www.oracledatabase12g.com. 版权所有.文章允许转载,但必须以链接方式注明源地址, 否则追究法律责任. 相关文章 | Related Posts: 1. How to check and disable Adaptive Cursor Sharing in 11g 2. How to Re-Organize a Table Online 3. 解决 ORA-14098 分区交换索引不匹配错误 4. Oracle SQL Developer 的一个 Bug 5. 滚动游标失效(Rolling Cursor Invalidations) 6. SCRIPT: VALIDATE.SQL to ANALYZE .. VALIDATE STRUCTURE objects in a Tablespace 7. SQL PLAN MANAGEMENT 8. How to find error message from OMS repository