ORACLE系统包DBMS_REDEFINITION实现表的在线重定义

ORACLE自带的DBMS_REDEFINITION包功能非常强大,可以用于降低高水位线,回收碎片空间,对表做在线重定义(添加或删除字段,改变字段类型,普通表重定义表为分区表,分区表重定义表为普通表等等)

另外,它有一个非常强大的功能,“在线”二字体现得淋漓尽致,但是也并不是完全的在线,因为在完成重定义前的最后一下,会持会表级排他锁,但这个锁定时间是可控的。

如果你也曾为delete无法降低高水位线而烦恼或者由于历史表太大导致维护困难,我相信这篇文章将对你有很大的感触,因此相信绝大朋友都用过诸如exp/imp,EXPDP/IMPDP,SHINK SPACE,MOVE等释放碎片,但业务影响范围非常大,相比之下DBMS_REDEFINITION的方式就有太多的优势了!

以下,拿普通表在线重定义成分区表为例,演示历史表过大导致维护困难:

SQL> list

1* create table ori_tab tablespace users as select * from ab

SQL> select count(*) from ori_tab;

COUNT(*)

----------

100

SQL> SQL> ed

Wrote file afiedt.buf

1  begin

2    dbms_stats.gather_table_stats( ‘T1‘,‘ORI_TAB‘ );

3* end;

SQL> /

PL/SQL procedure successfully completed.

SQL> select blocks,empty_blocks from user_tables where table_name=‘ORI_TAB‘;

BLOCKS EMPTY_BLOCKS

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

4       0               <<<<占用4个数据块

SQL>  delete from ori_tab where a > 50;

50 rows deleted.

SQL> COMMIT;

Commit complete.

SQL> select count(distinct dbms_rowid.rowid_block_number(rowid)) from ori_tab;

COUNT(DISTINCTDBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID))

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

1        <<<<<<<<<实际数据只占用1个数据块,说明delete操作并没有回收高水位线

SQL> alter table ori_tab add constraint oritab_a_pk primary key (a);    ---为表创建主键,为了在线重定做准备(重定义可以有两种方式rowid或主键_not NULL)

Table altered.

+++1检查ORI_TAB是否支持在线重定义

SQL> exec dbms_redefinition.can_redef_table(uname => ‘T1‘,tname => ‘ORI_TAB‘);

PL/SQL procedure successfully completed.

没有报错,说明当前表支持在线重定义

+++2创建新表INT_TAB

SQL> ed

Wrote file afiedt.buf

1  CREATE TABLE int_tab

2  ( a number

3  , b varchar2(2)

4  )

5    PARTITION BY RANGE (a)

6  ( PARTITION p0 VALUES LESS THAN (10),

7    PARTITION p1 VALUES LESS THAN (20),

8    PARTITION p2 VALUES LESS THAN (30),

9  PARTITION p3 VALUES LESS THAN (40),

10*  PARTITION p4 values less than (maxvalue))

SQL> /

Table created.

+++3 开始做

SQL> alter session force parallel dml parallel 4;

Session altered.

SQL> alter session force parallel query parallel 4;

Session altered.

SQL> exec dbms_redefinition.start_redef_table(uname => ‘T1‘,orig_table => ‘ORI_TAB‘,int_table => ‘INT_TAB‘,col_mapping => NULL,options_flag => DBMS_REDEFINITION.CONS_USE_PK);

PL/SQL procedure successfully completed.

SQL> SELECT COUNT(*) FROM INT_TAB;

COUNT(*)

----------

50       <<<<<<<已经看到数据被复制过去了

SQL> select index_name from user_indexes where table_name=‘INT_TAB‘;

no rows selected               <<<<<<<<<<<<索引还未自动创建

SQL> change/INT_TAB/ORI_TAB

1* select index_name from user_indexes where table_name=‘ORI_TAB‘

SQL> /

INDEX_NAME

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

ORITAB_A_PK

+++4 COPY相关对象(索引,触发器,视图等)

SQL> INSERT INTO ORI_TAB VALUES(51,‘NW‘);

1 row created.

SQL> COMMIT;

Commit complete.

SQL> SELECT COUNT(*) FROM ORI_TAB;

COUNT(*)

----------

51              <<<<源本是51条记录

SQL> SELECT COUNT(*) FROM INT_TAB;

COUNT(*)

----------

50              <<<<新表依旧是50条记录

SQL> ed

Wrote file afiedt.buf

1  DECLARE

2    num_errors PLS_INTEGER;

3  BEGIN

4    DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(‘T1‘,

5            ‘ORI_TAB‘,

6            ‘INT_TAB‘,

7            DBMS_REDEFINITION.CONS_ORIG_PARAMS,

8            TRUE,

9            TRUE,

10            TRUE,

11            TRUE,

12            num_errors);

13* END;

SQL> /

PL/SQL procedure successfully completed.

SQL> SELECT COUNT(*) FROM ORI_TAB;

COUNT(*)

----------

51

SQL> SELECT COUNT(*) FROM INT_TAB;

COUNT(*)

----------

50

SQL> select index_name from user_indexes where table_name=‘INT_TAB‘;

INDEX_NAME

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

TMP$$_ORITAB_A_PK0                   <<<<索引已经被自动创建

+++5 源表与新表做同步

SQL> exec dbms_redefinition.sync_interim_table(‘T1‘,‘ORI_TAB‘,‘INT_TAB‘);

PL/SQL procedure successfully completed.

SQL> SELECT COUNT(*) FROM ORI_TAB;

COUNT(*)

----------

51

SQL> SELECT COUNT(*) FROM INT_TAB;

COUNT(*)

----------

51                 <<<<<说明如果源表被更新频繁,我们也可以通过该方法使源表与新表尽可能多地进行数据同步

注:SYNC的程序决定了下面一步FINSH的时间长短,因为在线重定义方法在最后一步会对表持有表级排他锁。

+++6 完成在线重定义

SQL> exec dbms_redefinition.finish_redef_table(‘T1‘,‘ORI_TAB‘,‘INT_TAB‘);

PL/SQL procedure successfully completed.

另一个窗口查询源表ORI_TAB:

SQL> /

COUNT(*)

----------

51

SQL> /

/

/                 <<<<<<<此时持有表级排他锁

COUNT(*)

----------

51

SQL>

COUNT(*)

----------

51

SQL>

COUNT(*)

----------

51

至此,表的在线重定义就算完成了,原理就是通过一个临时段对旧数据进行同步,最终将旧数据段切换为生产。因此该方法对可用空间有要求,需要额外的空间进行数据同步并保存。

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

本文来自于我的技术博客 http://blog.csdn.net/robo23

转载请标注源文链接,否则追究法律责任!

时间: 2024-12-20 14:50:19

ORACLE系统包DBMS_REDEFINITION实现表的在线重定义的相关文章

Oracle已有数据表建立表分区—在线重定义

今天在做数据抽取的时候,发现有一张业务表数据量达到了5000W,所以就想将此表改为分区表.分区表的有点如下: 1.改善查询性能:对分区对象的查询可以仅搜索自己关心的分区,提高检索速度.2.增强可用性:如果表的某个分区出现故障,表在其他分区的数据仍然可用:3.维护方便:如果表的某个分区出现故障,需要修复数据,只修复该分区即可:4.均衡I/O:可以把不同的分区映射到磁盘以平衡I/O,改善整个系统性能. 第一步:首先对要在线重定义的表自行验证,看该表是否可以重定义,如果不可以则会提示错误信息 SQL>

如何对已经存在数据的表进行在线重定义方式实现分区

转一位大神的笔记. Oracle的普通表没有办法通过修改属性的方式直接转化为分区表,必须通过重建的方式进行转变,下面介绍三种效率比较高的方法,并说明它们各自的特点. 方法一:利用原表重建分区表. 步骤: SQL> CREATE TABLE T (ID NUMBER PRIMARY KEY, TIME DATE); 表已创建. SQL> INSERT INTO T SELECT ROWNUM, CREATED FROM DBA_OBJECTS; 已创建6264行. SQL> COMMIT;

Oracle在线重定义DBMS_REDEFINITION 普通表—&gt;分区表

实验环境:RHEL 6.4 + Oracle 11.2.0.3实验:在线重定义 普通表 为 分区表,包括主键对应的索引都改造为分区索引. 1,构造普通表t_objects conn test1/test1; create table t_objects as select * from dba_objects; SQL> select count(1) from t_objects; COUNT(1) ---------- 468738 --t_objects建立主键和索引 alter tabl

dbms_redefinition在线重定义表结构 可以在表分区的时候使用

dbms_redefinition在线重定义表结构 (2013-08-29 22:52:58) 转载▼ 标签: dbms_redefinition 非分区表转换成分区表 王显伟 在线重定义表结构 在线转换非分区表 分类: ORACLE新特性实践 刚接手一套系统应用数据库,因为项目建设期间种种原因,库是非归档模式也没有备份,更让我无语的是有个表增长的比较快,将近90G大小,每隔一段时间都要删除前三个月以前的数据,然后再用shrink收缩空间,因为是非分区表,shrink很是浪费时间,而且很多时间无

oracle在线重定义表

在一个高可用系统中,如果需要改变一个表的定义是一件比较棘手的问题,尤其是对于7×24系统.Oracle提供的基本语法基本可以满足一般性修改,但是对于把普通堆表改为分区表,把索引组织表修改为堆表等操作就无法完成了.而且,对于被大量DML语句访问的表,幸运的是,Oracle从9i版本开始提供了在线重定义表功能,通过调用DBMS_REDEFINITION包,可以在修改表结构的同时允许DML操作. 在线重定义表具有以下功能:修改表的存储参数:可以将表转移到其他表空间:增加并行查询选项:增加或删除分区:重

Oracle在线重定义(online redefinition)--将普通表改为分区表

使用Oracle的在线重定义技术,可以将Oracle的普通表改为分区表.操作如下: STEP1:测试表是否可以在线重定义,这里以unixdev数据库的LIJIAMAN.BSTEST为例 EXEC DBMS_REDEFINITION.CAN_REDEF_TABLE('LIJIAMAN','BSTEST', DBMS_REDEFINITION.CONS_USE_PK); 如果表上没有主键,则会报错:SQL> exec dbms_redefinition.start_redef_table('LIJI

oracle普通表转分区表(在线重定义方式)

1.1.TAB_TAOBAO_BILL 1.1.1检查下这张表是否可以在线重定义,无报错表示可以,报错会给出错误信息: exec dbms_redefinition.can_redef_table('ycheng', 'P_TAB_TAOBAO_BILL'); 1.1.2.expdp导出表进行备份(这里的DATA_PUMP_1目录是/data1/dpdump) expdp \'\/ as sysdba\' directory=DATA_PUMP_1 tables=TAB_TAOBAO_BILL

使用ORACLE在线重定义将普通表改为分区表

1.首先建立测试表,并插入测试数据: create table myPartition(id number,code varchar2(5),identifier varchar2(20)); insert into myPartition values(1,'01','01-01-0001-000001'); insert into myPartition values(2,'02','02-01-0001-000001'); insert into myPartition values(3,

oracle 11g在线重定义 普通表变分区表

第一种方法使用主键id进行重定义--createusertestidentifiedby1accountunlock;--grantresource--grantcreateanytable,alteranytable,dropanytable,lockanytable,selectanytabletotest;--<1>创建测试表,以下使用在线重定义把表转换为分区表,created为分区键,object_id为.. v.17173.com/playlist_17354294.htmlv.17