Oracle Online Redefinition在线重定义

面对越来越多的7*24系统,运维人员进行工作可用的时间窗口变的越来越小。就在有限的时间窗口中,硬件检修、网络改造配置占据了很多时间。对数据库对象进行日常维护,越来越成为我们需要关注的问题。

 

进行数据重排、表分区、字段类型修改、字段增改这样的操作,在开发和测试环境上是比较容易进行的。即使数据表很大,操作耗时可能会很高,我们也能够通过一些非技术的手段赢取操作时间窗。但是对于投产系统而言,操作过程中的长时间锁定可能是业务不能接受的。这个时候,就可以考虑Oracle的一些Online操作技术。

 

在笔者之前的一些文章中,介绍过一些online处理方法,如删除海量数据表,暂时隐去unused特定数据列,11g中默认值列优化等等。本篇我们介绍OracleOnline Redefinition(在线重定义)特性。

 

1、  基础知识

 

Oracle Online Redefinition可以保证在数据表进行DDL类型操作,如插入、删除数据列,分区处理的时候,还能够支持DML操作,特别是insert/update/delete操作。

 

对一般的DDL过程而言,Oracle都会给数据对象一个独占表锁。也就是说,在进行DDL操作的过程中,我们是不能对数据表进行DML(增加、修改和删除操作)。只有等待DDL结束,才能够继续操作。

 

也就是说,如果一个DDL持续时间很长,比如数据表海量大小,那么在这个长时间中,系统数据表其实是不能对外提供服务的。

 

Oracle在线重定义提供了解决问题的途径。我们如果需要对一个数据表进行重定义,需要定义一个中间目标表Interim。在Interim表中定义好目标结构,比如期望的存储、分区、字段关系。在线重定义使用的主要是dbms_redefinition包的对应方法。

 

在线重定义最大的特点是,当进行online操作的时候,我们还可以对数据表进行DML操作。结束定义过程时,期间进行的操作都是可以反馈到目标数据表中的。

 

目前,Oracle在线重定义支持下列种类的重定义动作:

 

ü  插入、删除数据表列和对一个存在的数据表列改名;

ü  修改字段类型;

ü  消除数据表段中的碎片块;

ü  索引、约束等对象的重定义;

ü  分区表转变;

 

下面,我们通过一个简单的例子,去看看如何使用dbms_redefinition包进行重定义操作。

 

2、简单的重定义例子

 

我们在Oracle 11gR2中进行测试实验。

 

 

SQL> select * from v$version where rownum<3;

 

BANNER

--------------------------------------------------------------------------------

Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - Production

PL/SQL Release 11.2.0.3.0 – Production

 

 

首先我们创建目标数据表。

 

 

SQL> create table t as select object_id, object_name, owner from dba_objects;

 

Table created

Executed in 0.328 seconds

 

SQL> select count(*) from t;

 

  COUNT(*)

----------

     75192

 

Executed in 0.047 seconds

 

SQL> alter table t add constraint pk_t_id primary key (object_id);

Table altered

 

 

进行在线重定义的第一步,就是判断目标数据表是否可以进行重定义。此时,可以使用dbms_redefinition包的can_redef_table方法进行判断。

 

 

SQL> exec dbms_redefinition.can_redef_table( 'SCOTT','T',dbms_redefinition.cons_use_pk);

PL/SQL procedure successfully completed

 

Executed in 0.016 seconds

 

 

注意该方法的第三个参数,使用主键还是rowid方法。本质上,Online Redefinition是使用物化视图Materialized View技术。过程定义记录就是主键和rowid两种策略。通常而言,我们还是推荐数据表有一个明确主键,也就是使用cons_use_pk。如果希望使用rowid,就使用dbms_redefinition.cons_use_rowid

 

通过了检查之后,就可以进行下一步,定义目标数据表格式。无论是何种变化,我们需要创建一个中间表interim,将我们“期望”的数据表定义实现在里面。其中包括表类型、列定义、分区定义和索引等。但是注意,约束(主外键)可以不定义在其中。

 

 

SQL> create table t_interim as select * from dba_objects where 1=0;

Table created

 

Executed in 0.032 seconds

 

 

显然,我们是希望给数据表T增加一些列。

 

此时,我们就可以开始重定义过程。使用dbms_redefinitionstart_redef_table方法。

 

 

SQL> exec dbms_redefinition.start_redef_table('SCOTT','T','T_INTERIM',col_mapping => 'object_id object_id, object_name object_name, owner owner',options_flag => dbms_redefinition.cons_use_pk);

 

PL/SQL procedure successfully completed

 

Executed in 0.625 seconds

 

 

此处注意参数col_mapping,这里以配对键值的方式定义了源数据表和中间表在列关系上的对应关系。每个列关系按照<源列名 目标列名>的格式进行书写。

 

对约束的处理,如果有需要转换的约束对象,我们可以使用copy_table_dependents方法将source数据表的约束拷贝到目标对象中。

 

 

SQL> declare

  2    error_count number;

  3  begin

  4    error_count := 0;

  5    dbms_redefinition.copy_table_dependents(uname => 'SCOTT',orig_table => 'T',

  6                                            int_table => 'T_INTERIM',

  7                                            copy_indexes => dbms_redefinition.cons_orig_params,

  8                                            num_errors => error_count);

  9    dbms_output.put_line(to_char(error_count));

 10  end;

 11  /

 

0

 

PL/SQL procedure successfully completed

 

Executed in 4.265 seconds

 

 

这个方法的参数很多,定义如下:

 

 

  --  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 privileges, FALSE

  --                                otherwise

  --           ignore errors      - TRUE implies continue after errors, FALSE

  --                                otherwise

  --           num_errors         - number of errors that occurred while

  --                                cloning ddl

  --           copy_statistics    - TRUE implies copy table statistics, FALSE

  --                                otherwise.

  --                                If copy_indexes is 1, copy index

  --                                related statistics, 0 otherwise.

  --           copy_mvlog         - TRUE implies copy table's MV log, FALSE

  --                                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,

                                  copy_mvlog         IN  BOOLEAN := FALSE);

 

 

利用各种copy_xxx参数,我们可以精细的定义哪些约束依赖关系会被拷贝到目标表中。

 

当结束之后,我们需要使用finish_redef_table方法结束定义过程。

 

 

SQL> exec dbms_redefinition.finish_redef_table('SCOTT','T','T_INTERIM');

PL/SQL procedure successfully completed

 

Executed in 1.406 seconds

 

 

最后,我们查看效果。

 

 

SQL> desc t;

Name           Type          Nullable Default Comments

-------------- ------------- -------- ------- --------

OWNER          VARCHAR2(30)  Y                        

OBJECT_NAME    VARCHAR2(128) Y                        

SUBOBJECT_NAME VARCHAR2(30)  Y                         

OBJECT_ID      NUMBER        Y                        

DATA_OBJECT_ID NUMBER        Y                        

OBJECT_TYPE    VARCHAR2(19)  Y                        

CREATED        DATE          Y                        

LAST_DDL_TIME  DATE          Y                        

TIMESTAMP      VARCHAR2(19)  Y                        

STATUS         VARCHAR2(7)   Y                        

TEMPORARY      VARCHAR2(1)   Y                        

GENERATED      VARCHAR2(1)   Y                        

SECONDARY      VARCHAR2(1)   Y                        

NAMESPACE      NUMBER        Y                        

EDITION_NAME   VARCHAR2(30)  Y                        

 

SQL> desc t_interim;

Name        Type          Nullable Default Comments

----------- ------------- -------- ------- --------

OBJECT_ID   NUMBER                                 

OBJECT_NAME VARCHAR2(128) Y                        

OWNER       VARCHAR2(30)  Y                        

 

SQL> select count(*) from t;

 

  COUNT(*)

----------

     75192

 

 

数据表T的字段被添加上,而中间表的结构被设置为原来的样子。约束内容,也就是原来的主键也被保留下来。

 

 

--dbms_metadata.getddl输出片段

         "EDITION_NAME" VARCHAR2(30),

          CONSTRAINT "PK_T_ID" PRIMARY KEY ("OBJECT_ID")

 

 

至此,我们完成了一个最简单的重定义过程。大致分为五个步骤:

 

ü  判断数据表是否可以支持重定义,定义中间表Interim结构;

ü  使用dbms_redefinitionstart_redef_table方法开始重定义过程;

ü  拷贝约束、重定义register约束信息内容;

ü  同步online过程中的DML操作(Optional,在之后例子演示);

ü  结束过程finish_redef_table操作;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值