Oracle Redefine table online will clone and exchange source and intermedia table - 1

在线重定义表是一个非常好用的功能, 也是一个比较老的话题了.
在Oracle中可以使用DBMS_REDEFINITION包对表进行重定义, 例如把单表重定义成分区表.

但是在线重定义需要耗费多少空间, 又是否需要move rows呢?

我个人认为是需要移动行的, 因为每个分区对应一个segemnt, segment是由extents组成, 每个extents又是由连续的block组成.

因此单表在拆分成分区后, segment势必要变成多个, 而在原始表中一个block里面可能包含了属于多个分区的记录, 那么势必会需要涉及move rows.

以上是我的个人分析, 那实际上是怎么样的呢?

先来看一个例子 : 

这个例子错开插入不同大小的ID记录, 确保分区SEGMENT不能连续的拆分BLOCK。

oracle@db1-> sqlplus "/ as sysdba"
SQL*Plus: Release 10.2.0.4.0 - Production on Thu Sep 13 18:57:51 2012
Copyright (c) 1982, 2007, Oracle.  All Rights Reserved.
Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

// 连接到test库

SQL> conn test/test

// 创建测试表

SQL> create table test.tbl_redefine_test(id int primary key,info varchar2(64) default 'Hello, I_am_digoal.zhou.', crt_time date default sysdate) tablespace kefu;
Table created.

查看索引, 将索引改成nologging的, 提高插入的性能

SQL> select index_name from user_indexes where table_name='TBL_REDEFINE_TEST';
INDEX_NAME
------------------------------
SYS_C0028986
SQL> alter index SYS_C0028986 nologging;
Index altered.

// 错开ID的范围插入将近20W条记录.

insert into tbl_redefine_test nologging (id)  select rownum from dual connect by level < 100000;
insert into tbl_redefine_test nologging (id)  select rownum+200000 from dual connect by level < 100000;
insert into tbl_redefine_test nologging (id)  select rownum+500000 from dual connect by level < 100000;
insert into tbl_redefine_test nologging (id)  select rownum+400000 from dual connect by level < 100000;
insert into tbl_redefine_test nologging (id)  select rownum+100000 from dual connect by level < 100000;
insert into tbl_redefine_test nologging (id)  select rownum+900000 from dual connect by level < 100000;
insert into tbl_redefine_test nologging (id)  select rownum+700000 from dual connect by level < 100000;
insert into tbl_redefine_test nologging (id)  select rownum+300000 from dual connect by level < 100000;
insert into tbl_redefine_test nologging (id)  select rownum+1000000 from dual connect by level < 100000;
insert into tbl_redefine_test nologging (id)  select rownum+600000 from dual connect by level < 100000;
insert into tbl_redefine_test nologging (id)  select rownum+800000 from dual connect by level < 100000;
insert into tbl_redefine_test nologging (id)  select rownum+1200000 from dual connect by level < 100000;
insert into tbl_redefine_test nologging (id)  select rownum+1500000 from dual connect by level < 100000;
insert into tbl_redefine_test nologging (id)  select rownum+1400000 from dual connect by level < 100000;
insert into tbl_redefine_test nologging (id)  select rownum+1100000 from dual connect by level < 100000;
insert into tbl_redefine_test nologging (id)  select rownum+1900000 from dual connect by level < 100000;
insert into tbl_redefine_test nologging (id)  select rownum+1700000 from dual connect by level < 100000;
insert into tbl_redefine_test nologging (id)  select rownum+1300000 from dual connect by level < 100000;
insert into tbl_redefine_test nologging (id)  select rownum+2000000 from dual connect by level < 100000;
insert into tbl_redefine_test nologging (id)  select rownum+1600000 from dual connect by level < 100000;
insert into tbl_redefine_test nologging (id)  select rownum+1800000 from dual connect by level < 100000;
commit;

// 登陆到超级用户准备在线重定义表, 拆成分区表

SQL> conn / as sysdba
Connected.
SQL> set timing on

// 首先查看原始表的起始BLOCK ID以及占用的空间大小53531 , 109051904

SQL> set pagesize 50000 linesize 190
SQL> column owner format a16
SQL> column SEGMENT_NAME format a32
SQL> select owner,segment_name,partition_name,header_block,bytes,extents,relative_fno from dba_segments where segment_name='TBL_REDEFINE_TEST';
OWNER            SEGMENT_NAME                     PARTITION_NAME                 HEADER_BLOCK      BYTES    EXTENTS RELATIVE_FNO
---------------- -------------------------------- ------------------------------ ------------ ---------- ---------- ------------
TEST             TBL_REDEFINE_TEST                                                      53531  109051904         84            5

// 使用DBMS_REDEFINITION.CAN_REDEF_TABLE检查原始表是否满足在线重定义条件

SQL> BEGIN
  2    DBMS_REDEFINITION.CAN_REDEF_TABLE('TEST','TBL_REDEFINE_TEST',
  3        DBMS_REDEFINITION.CONS_USE_PK);
  4  END;
  5  /
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.11

// 创建中间表(分区表)

SQL> CREATE TABLE test.part_test
        (id int primary key,info varchar2(64) default 'Hello, I_am_digoal.zhou.', crt_time date default sysdate)
  3       PARTITION BY RANGE(id)
  4         (PARTITION p1 VALUES LESS THAN (300000) TABLESPACE kefu,
  5          PARTITION p2 VALUES LESS THAN (600000) TABLESPACE kefu,
  6  PARTITION p3 VALUES LESS THAN (900000) TABLESPACE kefu,
  7  PARTITION p4 VALUES LESS THAN (1200000) TABLESPACE kefu,
  8  PARTITION p5 VALUES LESS THAN (1500000) TABLESPACE kefu,
  9  PARTITION p6 VALUES LESS THAN (1800000) TABLESPACE kefu,
 10  PARTITION p7 VALUES LESS THAN (2100000) TABLESPACE kefu
 11  );
Table created.
Elapsed: 00:00:00.06

// 在线重定义, 从这次操作的时间上可以看出, 这里应该发生了大量数据的拷贝.

SQL> BEGIN
  2    DBMS_REDEFINITION.START_REDEF_TABLE('TEST', 'TBL_REDEFINE_TEST','PART_TEST',
  3         'id id, info info, crt_time crt_time',
  4          dbms_redefinition.cons_use_pk);
  5  END;
  6  /
PL/SQL procedure successfully completed.
Elapsed: 00:00:07.20
//克隆对象 权限, 约束, 触发器等.
//This procedure clones the dependent objects of the table being redefined onto the interim table and registers the dependent objects. This procedure does not clone the already registered dependent objects.
This subprogram is used to clone the dependent objects like grants, triggers, constraints and privileges from the table being redefined to the interim table (which represents the post-redefinition table).
SQL> DECLARE
  2  num_errors PLS_INTEGER;
  3  BEGIN
  4    DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS('TEST', 'TBL_REDEFINE_TEST','PART_TEST',
  5     DBMS_REDEFINITION.CONS_ORIG_PARAMS, TRUE, TRUE, TRUE, TRUE, num_errors);
  6  END;
  7  /
PL/SQL procedure successfully completed.
Elapsed: 00:00:02.49

// 几个报错, 需要忽略, 因为克隆过程会用到重名的约束. 并通过下面的SQL查询是否有其他错误. 

// Note that the ignore_errors argument is set to TRUE for this call. The reason is that the interim table was created with a primary key constraint, and when COPY_TABLE_DEPENDENTS attempts to copy the primary key constraint and index from the original table, errors occurs. You can ignore these errors, but you must run the query shown in the next step to see if there are other errors.

SQL> select object_name, base_table_name, ddl_txt from
  2           DBA_REDEFINITION_ERRORS;

OBJECT_NAME                    BASE_TABLE_NAME
------------------------------ ------------------------------
DDL_TXT
--------------------------------------------------------------------------------
SYS_C0028986                   TBL_REDEFINE_TEST
CREATE UNIQUE INDEX "TEST"."TMP$$_SYS_C00289860" ON "TEST"."PART_TEST" ("ID")

SYS_C0028986                   TBL_REDEFINE_TEST
ALTER TABLE "TEST"."PART_TEST" ADD CONSTRAINT "TMP$$_SYS_C00289860" PRIMARY KEY
Elapsed: 00:00:00.02

// 同步中间表数据和原始表的数据

SQL> BEGIN
  2    DBMS_REDEFINITION.SYNC_INTERIM_TABLE('TEST', 'TBL_REDEFINE_TEST', 'PART_TEST');
  3  END;
  4  /
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.02

// 这一步前, 可以对中间表进行添加索引等操作, 在完成这个操作后, 原始表将被重定义成中间表的形态, 因此原始表在此步骤会短暂的被锁. This procedure completes the redefinition process. Before this step, you can create new indexes, triggers, grants, and constraints on the interim table. The referential constraints involving the interim table must be disabled. After completing this step, the original table is redefined with the attributes and data of the interim table. The original table is locked briefly during this procedure

SQL> BEGIN
  2    DBMS_REDEFINITION.FINISH_REDEF_TABLE('TEST', 'TBL_REDEFINE_TEST', 'PART_TEST');
  3  END;
  4  /
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.46

// 完成后查看, 无重定义错误

SQL> select object_name, base_table_name, ddl_txt from DBA_REDEFINITION_ERRORS;
no rows selected
Elapsed: 00:00:00.00

// 结束后查看原始表的起始BLOCK ID以及占用的空间大小. (显然已经是7个分区了)

// 显然已经变成分区表了, 并且他们的BLOCKID都发生了变化, 已经不是原来的53531. 而是57755开始的BLOCKID, 跳过了4224个block.

SQL> set pagesize 50000 linesize 190
SQL> column owner format a16
SQL> column SEGMENT_NAME format a32
SQL> select owner,segment_name,partition_name,header_block,bytes,extents,relative_fno from dba_segments where segment_name='TBL_REDEFINE_TEST';
OWNER            SEGMENT_NAME                     PARTITION_NAME                 HEADER_BLOCK      BYTES    EXTENTS RELATIVE_FNO
---------------- -------------------------------- ------------------------------ ------------ ---------- ---------- ------------
TEST             TBL_REDEFINE_TEST                P1                                    57755   15728640         30            5
TEST             TBL_REDEFINE_TEST                P2                                    57763   15728640         30            5
TEST             TBL_REDEFINE_TEST                P3                                    57771   15728640         30            5
TEST             TBL_REDEFINE_TEST                P4                                    57779   15728640         30            5
TEST             TBL_REDEFINE_TEST                P5                                    57787   15728640         30            5
TEST             TBL_REDEFINE_TEST                P6                                    57795   15728640         30            5
TEST             TBL_REDEFINE_TEST                P7                                    57803   15728640         30            5
7 rows selected.
Elapsed: 00:00:00.01

再看另一个例子, ID是连续插入的, 如果ORACLE足够智能, 应该可以讲segment里面包含的blocks简单的SPLIT开来. 只需要move少量的rows.

但是结果还是同上一个例子一样, move了所有的行.

SQL> create table test.tbl_redefine_test(id int primary key,info varchar2(64) default 'Hello, I_am_digoal.zhou.', crt_time date default sysdate) tablespace kefu;
Table created.
Elapsed: 00:00:00.02
SQL> select index_name from user_indexes where table_name='TBL_REDEFINE_TEST';
INDEX_NAME
------------------------------
SYS_C0028988
Elapsed: 00:00:00.00
SQL> alter index SYS_C0028988 nologging;
Index altered.
Elapsed: 00:00:00.01
SQL> insert into tbl_redefine_test nologging (id)  select rownum from dual connect by level < 2000000;
1999999 rows created.
Elapsed: 00:00:08.27
SQL> commit;
Commit complete.
Elapsed: 00:00:00.03
SQL> conn /as sysdba
Connected.
SQL> set timing on
SQL> set pagesize 50000 linesize 190
SQL> column owner format a16
SQL> column SEGMENT_NAME format a32
SQL> select owner,segment_name,partition_name,header_block,bytes,extents,relative_fno from dba_segments where segment_name='TBL_REDEFINE_TEST';
OWNER            SEGMENT_NAME                     PARTITION_NAME                 HEADER_BLOCK      BYTES    EXTENTS RELATIVE_FNO
---------------- -------------------------------- ------------------------------ ------------ ---------- ---------- ------------
TEST             TBL_REDEFINE_TEST                                                      86811  100663296         83            5
Elapsed: 00:00:00.01
SQL> BEGIN
  2    DBMS_REDEFINITION.CAN_REDEF_TABLE('TEST','TBL_REDEFINE_TEST',
  3        DBMS_REDEFINITION.CONS_USE_PK);
  4  END;
  5  /
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.00
SQL> CREATE TABLE test.part_test
  2     (id int primary key,info varchar2(64) default 'Hello, I_am_digoal.zhou.', crt_time date default sysdate)
  3       PARTITION BY RANGE(id)
  4         (PARTITION p1 VALUES LESS THAN (300000) TABLESPACE kefu,
  5          PARTITION p2 VALUES LESS THAN (600000) TABLESPACE kefu,
  6  PARTITION p3 VALUES LESS THAN (900000) TABLESPACE kefu,
  7  PARTITION p4 VALUES LESS THAN (1200000) TABLESPACE kefu,
  8  PARTITION p5 VALUES LESS THAN (1500000) TABLESPACE kefu,
  9  PARTITION p6 VALUES LESS THAN (1800000) TABLESPACE kefu,
 10  PARTITION p7 VALUES LESS THAN (2100000) TABLESPACE kefu
 11  );
Table created.
Elapsed: 00:00:00.03
SQL> BEGIN
  2    DBMS_REDEFINITION.START_REDEF_TABLE('TEST', 'TBL_REDEFINE_TEST','PART_TEST',
  3         'id id, info info, crt_time crt_time',
  4          dbms_redefinition.cons_use_pk);
  5  END;
  6  /
PL/SQL procedure successfully completed.
Elapsed: 00:00:08.08
SQL> DECLARE
  2  num_errors PLS_INTEGER;
  3  BEGIN
  4    DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS('TEST', 'TBL_REDEFINE_TEST','PART_TEST',
  5     DBMS_REDEFINITION.CONS_ORIG_PARAMS, TRUE, TRUE, TRUE, TRUE, num_errors);
  6  END;
  7  /
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.14
SQL> select object_name, base_table_name, ddl_txt from
  2           DBA_REDEFINITION_ERRORS;                 

OBJECT_NAME                    BASE_TABLE_NAME                DDL_TXT
------------------------------ ------------------------------ --------------------------------------------------------------------------------
SYS_C0028988                   TBL_REDEFINE_TEST              CREATE UNIQUE INDEX "TEST"."TMP$$_SYS_C00289880" ON "TEST"."PART_TEST" ("ID")
SYS_C0028988                   TBL_REDEFINE_TEST              ALTER TABLE "TEST"."PART_TEST" ADD CONSTRAINT "TMP$$_SYS_C00289880" PRIMARY KE
                                                              Y
Elapsed: 00:00:00.00
SQL> BEGIN
  2    DBMS_REDEFINITION.SYNC_INTERIM_TABLE('TEST', 'TBL_REDEFINE_TEST', 'PART_TEST');
  3  END;
  4  /
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.08
SQL> BEGIN
  2    DBMS_REDEFINITION.FINISH_REDEF_TABLE('TEST', 'TBL_REDEFINE_TEST', 'PART_TEST');
  3  END;
  4  /
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.14
SQL> select object_name, base_table_name, ddl_txt from DBA_REDEFINITION_ERRORS;
no rows selected
Elapsed: 00:00:00.00
SQL> select owner,segment_name,partition_name,header_block,bytes,extents,relative_fno from dba_segments where segment_name='TBL_REDEFINE_TEST';
OWNER            SEGMENT_NAME                     PARTITION_NAME                 HEADER_BLOCK      BYTES    EXTENTS RELATIVE_FNO
---------------- -------------------------------- ------------------------------ ------------ ---------- ---------- ------------
TEST             TBL_REDEFINE_TEST                P1                                    91035   15728640         30            5
TEST             TBL_REDEFINE_TEST                P2                                    91043   15728640         30            5
TEST             TBL_REDEFINE_TEST                P3                                    91051   15728640         30            5
TEST             TBL_REDEFINE_TEST                P4                                    91059   15728640         30            5
TEST             TBL_REDEFINE_TEST                P5                                    91067   15728640         30            5
TEST             TBL_REDEFINE_TEST                P6                                    91075   15728640         30            5
TEST             TBL_REDEFINE_TEST                P7                                    91083   10485760         25            5
7 rows selected.
Elapsed: 00:00:00.01
SQL> select owner,segment_name,partition_name,header_block,bytes,extents,relative_fno from dba_segments where segment_name='PART_TEST';

OWNER            SEGMENT_NAME                     PARTITION_NAME                 HEADER_BLOCK      BYTES    EXTENTS RELATIVE_FNO
---------------- -------------------------------- ------------------------------ ------------ ---------- ---------- ------------
TEST             PART_TEST                                                              86811  100663296         83            5
Elapsed: 00:00:00.08
时间: 2024-09-16 17:25:18

Oracle Redefine table online will clone and exchange source and intermedia table - 1的相关文章

Oracle Redefine table online will clone and exchange source and intermedia table - 2

为了更加清晰的了解每一步的变化, 每一步都查看中间表和原始表的extents信息, 来看看. SQL> create table test.tbl_redefine_test(id int primary key,info varchar2(64) default 'Hello, I_am_digoal.zhou.', crt_time date default sysdate) tablespace kefu; SQL> select index_name from user_indexes

Oracle Redefine table online will clone and exchange source and intermedia table - 3

// 执行完START_REDEF_TABLE后, 中间表发生了巨大变化, 数据从原始表已经拷贝到中间表. SQL> BEGIN 2 DBMS_REDEFINITION.START_REDEF_TABLE('TEST', 'TBL_REDEFINE_TEST','PART_TEST', 3 'id id, info info, crt_time crt_time', 4 dbms_redefinition.cons_use_pk); 5 END; 6 / PL/SQL procedure suc

《Greenplum企业应用实战》一2.3 畅游Greenplum

2.3 畅游Greenplum 本节只介绍一些常用的命令,重点是Greenplum特有的一些命令,而对于一般数据库都具备的特性及SQL标准语法,本节提到的比较少,因此要求读者在阅读本节具备一定的SQL基础. 2.3.1 如何访问Greenplum psql psql是Greenplum/PostgreSQL默认的客户端,前面初始化数据库的时候已经使用过了,下面介绍一些详细的用法. ```javascript [gpadmin@dw-greenplum-1 ~]$ psql --help This

Greenplum 清理垃圾、修改存储模式(行列变换) 平滑方法 - 交换数据、交互分区

标签 PostgreSQL , Greenplum , 交换分区 , 清理垃圾 , 存储格式变更 背景 1.在使用Greenplum的过程中,如果业务会经常对数据进行更新,删除,插入,可能导致数据出现膨胀. <如何检测.清理Greenplum膨胀.垃圾 - 阿里云HybridDB for PG最佳实践> <Greenplum 列存表(AO表)的膨胀.垃圾检查与空间收缩> 2.用户在建表的时候,存储模式选择不当,但是业务已经运行了一段时间,表里面已经写入了大量的数据. 3.用户在建表

Oracle Flashback table使用示例

确保recyclebin是打开的 SQL> show parameter recyclebin NAME                                 TYPE        VALUE ------------------------------------ ----------- ------------------------------ recyclebin                           string      ON 创建一张表 SQL> cre

Oracle Table的创建参数

先看一个oracle 10g 下table 创建SQL,都是默认值: CREATE TABLE SYS.QS ( USERNAME  VARCHAR2(30 BYTE)                   NOT NULL, USER_ID   NUMBER                              NOT NULL, CREATED   DATE                                NOT NULL ) TABLESPACE SYSTEM PCTUSE

PostgreSQL Oracle 兼容性之 - rowid (CREATE TABLE WITH OIDS)

标签 PostgreSQL , Oracle , 兼容性 , 行号 , rowid , oid , ctid 背景 Oracle的数据中,通过ROWID可以定位到一条记录,当记录没有发生行迁移时,ROWID是不变的,因此即使不使用PK,也能很好的定位到一条记录. PostgreSQL中,也有行号,CTID,由BLOCK_ID和ITEM_ID组成,即哪个数据块的哪条记录. 但是PostgreSQL的引擎为多版本引擎,因此一条记录在被更新后CTID会发生变化(代表了新的版本). 不管是Oracle还

PostgreSQL Oracle 兼容性 之 TABLE、PIPELINED函数

标签 PostgreSQL , 返回表 , 返回复合类型 , 返回游标 背景 Oracle 通过table, pipelined函数,用于格式化返回类型为table的函数的结果. Table function concepts There a couple of steps to take when you are working with table functions. Like when you are working with normal tables you have to desc

Oracle 临时事务表 全局临时表_global temporary table

所有的操作都在一个事务里,事务提交后,此表清空,特别适合做插入删除频率特别高的临时表操作,比如插入完数据就开始查询,查询完就删掉等,用完就扔! 临时表分事务级临时表和会话级临时表. 事务级临时表只对当前事务有效,通过语句:ON COMMIT DELETE ROWS 指定. 会话级临时表对当前会话有效,通过语句:ON COMMIT PRESERVE ROWS语句指定. -- Create table create global temporary table WFM_TMP_WORKLIST (