LIUBINGLIN

很多时候不在于你技术有多高,更重要的是你够不够细心、耐心和静心。

  • 博客访问: 5091384
  • 博文数量: 493
  • 用 户 组: 普通用户
  • 注册时间: 2010-01-05 23:06
  • 认证徽章:
个人简介

Oracle数据库管理员,Oracle数据库系统构架员;2012年7月出版《构建最高可用Oracle数据库系统:Oracle 11gR2 RAC管理、维护与性能优化》一书;Oracle 10g OCM。

文章分类

全部博文(493)

分类: Oracle

2015-08-07 21:57:37


   这篇文章参考官方文档,简单讨论一下使用DBMS_REDEFINITION包执行在线重定义表。在线重定义表技术是从9i开始就出现的技术,该技术可以有效的减少对表逻辑结构和物理结构的调整给业务系统带来的影响,在对某个表做在线重定义操作的过程并不影响对原表的查询和DML操作,只是在结束在线重定义操作的时候会对原表有短暂的锁定。在线重定义和传统方法相比,增强了数据库的可用性。对表的在线重定义由于要产生中间表,所以要求剩余至少和原表空间相同,甚至更大。在线重定义功能实际是通过物化视图来实现的。我们可以使用OEM或者DBMS_REDEFINITION包完成在线重定义操作。

在线表重定义可以达到以下的目的:
1).修改表或集群的存储参数。
2).移动表或集群到不同的表空间。
3).增加,修改或者DROP表或集群的一个或多个字段。
4).改变分区结构。
5).改变单一表分区的物理属性,包括一定它到相同用户的不同表空间下。
6).改变物化视图日志的物理属性或者Oracle Streams高级队列队列表。
7).添加并行查询支持。
8).重建表或者集群减少碎片,在很多情况下,在线段shrink是减少碎片更容易的方法。
9).将普通表转换为IOT,或者将IOT转换为普通表。
10).转换一个相关表到表的对象字段,或者反向转换。
11).转换一个对象表到相关的表或者表的对象字段,或者反向转换。


普通用户要想使用DBMS_REDEFINITION包,需要拥有以下权限:

EXECUTE_CATALOG_ROLE角色。
CREATE ANY TABLE.
ALTER ANY TABLE.
DROP ANY TABLE.
LOCK ANY TALBE.
SELECT ANY TABLE.

执行COPY_TABLE_DEPENDENTS过程还需要以下权限:
CREATE ANY TRIGGER.
CREATE ANY INDEX.

下面讨论一下使用DBMS_REDEFINITION包执行在线重定义表的步骤:

1.选择重定义方法:by key或者by rowid

    By key,选择主键或者所有字段有NOT NULL约束的唯一键用于在线重定义操作。使用这种方法,在线重定义之前和之后表应该有相同的主键字段,这是在线重定义操作默认和优先选择的方法。

    By rowid,如果没有主键可以使用这种方法,使用这种方法,隐藏字段M_ROW$$被添加到重定义后的表中。推荐在重定义表之后将这个字段DROP掉,或者将其标记为UNUSED。如果COMPATIBLE初始化参数设置为10.2.0或者更高,最终在线重定义的语法将自动设置这个字段为UNUSED。可以使用ALTER TABLE ... DROP UNUSED COLUMNS语句DROP掉它。不能在索引组织表(IOT)上使用该方法。

2.验证表是否能被在线重定义。

   通过调用CAN_REDEF_TABLE过程验证表是否能被在线重定义。如果表不能作为在线重定义表的候选表,那么这个过程提示一个错误,并且会表明为什么该表不能在线重定
义。

3.创建一个空的中间表。

   按照期望的逻辑和物理属性在在线重定义的表相同的用户下创建一个空的中间表,如果要DROP字段,那么在中间表中不要包含它们,如果是新增加字段,那么在中间表中
添加这些字段,如果是修改字段,那么在中间表按照想要的结果修改它们。

创建中间表不是必须按照重定义的表创建所有的索引,约束,授权,和触发器。因为这些对象可以在下面的拷贝依赖对象的步骤中可以被自动定义。

4.启动行迁移功能。

   如果采用rowid的方法重定义一个分区表,启用中间表的行迁移功能。

ALTER TABLE ... ENABLE ROW MOVEMENT.

5.启用会话并行功能。

    这是可选的步骤,如果重定义一张大表,想通过并行方式提升下面步骤的性能,执行以下的语句:
ALTER SESSION FORCE PARALLEL DML PARALLEL <degree-of-parallelism>;
ALTER SESSION FORCE PARALLEL QUERY PARALLEL <degree-of-parallelism>;

6.开始在线重定义过程。

提供以下的信息调用START_REDEF_TABLE过程开始重定义过程:

>被在线重定义的用户名和表名。
>中间表名称。
>字段映射字符串,映射被重定义表的字段到中间表的字段。
>重定义方法。
 DBMS_REDEFINITION.CONS_USE_PK代表by key方法,这也是默认的方法。
 DBMS_REDEFINITION.CONS_USE_ROWID代表by rowid方法。
>在排序行中使用的字段。
>如果重定义的分区表只有一个分区,分区名。

 因为这步会拷贝数据,所以可能会持续一段时间,表在被重新定义的整个过程中,查询和DML操作仍然是可执行的。

注意:如果START_REDEF_TABLE以为某种原因失败,必须调用ABORT_REDEF_TABLE过程,否则接下来重新定义表将失败。

7.拷贝依赖的对象。

   重被重定义的表中拷贝依赖的对象(例如,触发器,索引,物化视图日志,授权和约束)和统计信息到中间表,使用以下两种方法的其中一种,方法一是首选的方法,因
为它是自动的,该方法也会拷贝统计信息到中间表。

>方法一:自动创建依赖对象
    使用COPY_TABLE_DEPENDENTS过程自动创建中间表的依赖对象,这个过程也叫做注册依赖对象。在重定义过程完成后,依赖对象的名字将和原有名字保持一致。

>方法二:手动创建依赖对象
    可以手动创建中间表的依赖对象,并且注册它们。

8.完成在线重定义过程。

   执行FINISH_REDEF_TABLE过程完成重定义表过程。在这个过程中,原始表将以排他模式被锁定非常短的时间,时间长短依赖于原始表中独立的(与中间表的数据差)数据
量,然而,FINISH_REDEF_TABLE在完成重定义之前将等待所有的DML操作提交。

9.处理M_ROW$$字段。

   如果使用rowid在线重定义,并且COMPATIBLE初始化参数设置为10.1.0或者更低,DROP或者设置重定义后的表中出现的M_ROW$$隐藏字段为UNUSED。

ALTER TABLE table_name set UNUSED(M_ROW$$);

   如果COMPATIBLE初始化参数为10.2.0或者更高,当重定义完成该隐藏字段将自动被设置为UNUSED。可以使用ALTER TABLE ... DROP UNUSED COLUMNS语句DROP该字段。


10.DROP中间表。

等待任何针对中间表长时间运行的查询完成,然后DROP中间表。


如果对活动的中间表查询执行DROP操作,可能收到ORA-08103的错误("object no longer exists")。


下面通过例子说明在线重定义表的过程:

1.验证表在线重定义的条件,使用主键方法进行在线重定义验证:
BEGIN
  DBMS_REDEFINITION.CAN_REDEF_TABLE('hr','admin_emp',
      DBMS_REDEFINITION.CONS_USE_PK);
END;
/

2.创建中间表hr.int_admin_emp:
CREATE TABLE hr.int_admin_emp
        (empno      NUMBER(5) PRIMARY KEY,
         ename      VARCHAR2(15) NOT NULL,
         job        VARCHAR2(10),
         mgr        NUMBER(5),
         hiredate   DATE DEFAULT (sysdate),
         sal        NUMBER(7,2),
         deptno     NUMBER(3) NOT NULL,
         bonus      NUMBER (7,2) DEFAULT(1000))
     PARTITION BY RANGE(empno)
       (PARTITION emp1000 VALUES LESS THAN (1000) TABLESPACE admin_tbs,
        PARTITION emp2000 VALUES LESS THAN (2000) TABLESPACE admin_tbs2);

3.开始重定义过程。
BEGIN
  DBMS_REDEFINITION.START_REDEF_TABLE('hr', 'admin_emp','int_admin_emp',
       'empno empno, ename ename, job job, deptno+10 deptno, 0 bonus',
        dbms_redefinition.cons_use_pk);
END;
/

4.拷贝依赖对象(自动在hr.int_admin_emp表上创建触发器,索引,物化视图日志,授权和约束)。
DECLARE
num_errors PLS_INTEGER;
BEGIN
  DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS('hr', 'admin_emp','int_admin_emp',
   DBMS_REDEFINITION.CONS_ORIG_PARAMS, TRUE, TRUE, TRUE, TRUE, num_errors);
END;
/
注意:在这儿ignore_errors参数设置为TRUE,根据实际情况,部分错误可直接忽略。

5.查询DBA_REDEFINITION_ERRORS试图查询错误:
SQL> select object_name, base_table_name, ddl_txt from
         DBA_REDEFINITION_ERRORS;
 
OBJECT_NAME   BASE_TABLE_NAME  DDL_TXT
------------- ---------------- ------------------------------
SYS_C005836   ADMIN_EMP        CREATE UNIQUE INDEX "HR"."TMP$
                               $_SYS_C0058360" ON "HR"."INT_A
                               DMIN_EMP" ("EMPNO")
 
SYS_C005836   ADMIN_EMP        ALTER TABLE "HR"."INT_ADMIN_EM
                               P" ADD CONSTRAINT "TMP$$_SYS_C
                               0058360" PRIMARY KEY

6.(可选),同步中间表。
BEGIN 
  DBMS_REDEFINITION.SYNC_INTERIM_TABLE('hr', 'admin_emp', 'int_admin_emp');
END;
/

7.完成重定义。
BEGIN
  DBMS_REDEFINITION.FINISH_REDEF_TABLE('hr', 'admin_emp', 'int_admin_emp');
END;
/

    hr.admin_emp将被以排他模式锁定很短的时间,直到这步结束,之后hr.admin_emp被重定义完成,hr.admin_emp将有hr.int_admin_emp表的所有属性。

8.等待任何针对中间表长时间运行的查询结束,然后DROP中间表。


    另外,在线重定义表可以通过OEM非常容易的完成在TABLE页面,选择要重定义表的字段,从Actions List中选择Reorganize。
   使用传统的表重定义方法可能遇到一些问题,可以参考文章《Oracle Database将普通表转换为分区表遇到的问题》:http://blog.itpub.net/23135684/viewspace-1753024/

    《使用DBMS_REDEFINITION在线重定义表普通表为分区表》:http://blog.itpub.net/23135684/viewspace-661756/


    本文节选自《Oracle Database Administrator's Guide 11g Release 2 (11.2) Part Number E25494-02》中的部分内容,更详细的内容和例子请参考这篇文章和对DBMS_REDEFINITION包的解释。

相关文章:
   《Moving表到新的段或者表空间http://blog.itpub.net/23135684/viewspace-1766480/

--end--

阅读(7480) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~

ZALBB2017-09-27 17:52:00

重定义前,记得检查新旧表的字段默认属性是否一致?这是个巨大的坑,

评论热议
请登录后评论。

登录 注册