Exchange partition分区结构的“乾坤挪移”

来源:互联网 发布:2016淘宝还能赚钱吗 编辑:程序博客网 时间:2024/04/26 15:19

分区表是我们面临海量数据环境中的一种方便常用的技术方案。根据业务系统的访问需求,将海量数据表分割为多个相对独立的数据段对象,可以有效的减少对海量数据全表的直接操作,提升整体性能。

 

Oracle为分区表提供了很多分区操作,用来方便分区表数据的管理。其中,exchange partition是用于实现分区与数据表之间的交换操作。从效果上看,exchange partition就是将一个分区中填满原先在一个数据表中的数据。但实际该操作的本质是什么呢?本篇通过实验来进行说明。

 

1、 实验环境说明和数据准备

 

我们使用Oracle 10gR2来进行试验。

 

 

SQL> select * from v$version;

 

BANNER

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

Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod

PL/SQL Release 10.2.0.1.0 - Production

CORE    10.2.0.1.0    Production

 

TNS for 32-bit Windows: Version 10.2.0.1.0 - Production

NLSRTL Version 10.2.0.1.0 Production

 

 

实验数据选择scott schema下的经典emp数据表。

 

 

SQL> create table t as select * from scott.emp;

 

Table created

 

 

 

2、 exchange partition实验

 

exchange partition语句的使用语法为:

 

 

alter table xxx exchange partition A with table B;

 

 

含义是将数据表xxx的分区A替换为数据表B的内容。首先,我们使用t中的数据,构建出替换数据子表。

 

 

SQL> create table t_part1 as select * from t where sal<3000;

 

Table created

 

SQL> create table t_part2 as select * from t where sal>=3000 and sal<5000;

 

Table created

 

 

构建了两个数据表t_part1和t_part2,保存sal字段小于3000和3000-5000的记录值。

 

两个数据表,我们分别查看数据字典中的元数据信息。

 

 

SQL> select object_name, object_id, data_object_id, object_type from dba_objects where wner='SYS' and object_name in ('T_PART1','T_PART2');

 

OBJECT_NAM  OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE

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

T_PART1         54439         54439 TABLE

T_PART2         54440         54440 TABLE

 

 

SQL> select segment_name, segment_type,HEADER_FILE, HEADER_BLOCK  from dba_segments where segment_name in ('T_PART1','T_PART2') and wner='SYS';

 

SEGMENT_NA SEGMENT_TYPE       HEADER_FILE HEADER_BLOCK

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

T_PART1    TABLE                       1        62377

T_PART2    TABLE                       1        62385

 

 

注意:数据表t_part1和t_part2是两个普通数据表,对应的data_object_id分别为54439和54440,段头对应的物理位置分别为(1,62377)和(1、62385)。data_object_id是Oracle内部对象的物理id编号,一定程度上反映了对象的物理位置信息。

 

之后,我们构建分区表,使用sal进行范围分区。

 

 

SQL> create table t_part

  2  (

  3    EMPNO    NUMBER(4),

  4    ENAME    VARCHAR2(10),

  5    JOB      VARCHAR2(9),

  6    MGR      NUMBER(4),

  7    HIREDATE DATE,

  8    SAL      NUMBER(7,2),

  9    COMM     NUMBER(7,2),

 10    DEPTNO   NUMBER(2)

 11  )

 12  partition by range(sal)

 13  (

 14    partition t_p1 values less than (3000),

 15    partition t_p2 values less than (5000)

 16  );

 

Table created

 

 

初始状态下,t_part分区表中没有数据。

 

 

SQL> select * from t_part;

 

EMPNO ENAME      JOB         MGR HIREDATE          SAL      COMM DEPTNO

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

 

 

我们检查分区表的元数据信息,如下:

 

 

SQL> select object_name, object_id, data_object_id, object_type from dba_objects where wner='SYS' and object_name in ('T_PART','T_P1','T_P2');

 

OBJECT_NAM  OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE

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

T_PART          54442         54442 TABLE PARTITION

T_PART          54443         54443 TABLE PARTITION

T_PART          54441                TABLE

 

 

 

SQL> select segment_name,PARTITION_NAME, segment_type,HEADER_FILE, HEADER_BLOCK  from dba_segments where segment_name in ('T_PART','T_P1','T_P2') and wner='SYS';

 

SEGMENT_NA PARTITION_NAME       SEGMENT_TYPE       HEADER_FILE HEADER_BLOCK

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

T_PART     T_P1                 TABLE PARTITION             1        62393

T_PART     T_P2                 TABLE PARTITION             1        62401

 

 

分区表是一种很特殊的段对象。通常情况下一个数据表对应一个段对象,只能分布在一个表空间中。而分区表(分区索引)是包括多个段对象,一个分区对应一个段对象,理论上可以分布在多个表空间中的。

 

我们通过数据字典检查,发现了数据表T_PART,虽然占据了对象dba_objects的一个条目,但是没有对应的物理属性编号data_object_id。而两个分区被承认为独立的分区,分配有象征物理段对象的data_object_id,分别为54442和54443。从段头信息来看,两个独立的段T_P1和T_P2,分别占据(1, 62393)和(1,62401)。

 

下面进行exchange partition实验。

 

 

SQL> alter table t_part exchange partition t_p1 with table t_part1;

Table altered

 

SQL> alter table t_part exchange partition t_p2 with table t_part2;

Table altered

 

SQL> select count(*) from t_part;

 

  COUNT(*)

----------

        13

 

SQL> select count(*) from t_part partition(t_p1);

 

  COUNT(*)

----------

        11

 

SQL> select count(*) from t_part partition(t_p2);

 

  COUNT(*)

----------

         2

 

 

经过alter table exchange partition命令,我们成功的进行了分区数据表信息的填入。下面,我们再次来观察一下数据表t_part1和t_part2,分区表t_part的对应信息和元数据内容。

 

//原有数据表中内容为空;

SQL> select * from t_part1;

 

EMPNO ENAME      JOB         MGR HIREDATE          SAL      COMM DEPTNO

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

 

SQL> select * from t_part2;

 

EMPNO ENAME      JOB         MGR HIREDATE          SAL      COMM DEPTNO

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

 

 

 

原有两个源数据表内容空空如也,似乎exchange partition操作不是简单的数据集合复制。

 

//对比dba_objects情况;

SQL> select object_name, object_id, data_object_id, object_type from dba_objects where wner='SYS' and object_name in ('T_PART1','T_PART2');

 

OBJECT_NAM  OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE

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

T_PART1         54439         54442 TABLE

T_PART2         54440         54443 TABLE

 

 

SQL> select object_name, object_id, data_object_id, object_type from dba_objects where wner='SYS' and object_name in ('T_PART','T_P1','T_P2');

 

OBJECT_NAM  OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE

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

T_PART          54442         54439 TABLE PARTITION

T_PART          54443         54440 TABLE PARTITION

T_PART          54441                TABLE

 

 

//对比dba_segments情况

SQL> select segment_name, segment_type,HEADER_FILE, HEADER_BLOCK  from dba_segments where segment_name in ('T_PART1','T_PART2') and wner='SYS';

 

SEGMENT_NAME         SEGMENT_TYPE    HEADER_FILE HEADER_BLOCK

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

T_PART1              TABLE                    1        62393

T_PART2              TABLE                    1        62401

 

SQL> select segment_name,PARTITION_NAME, segment_type,HEADER_FILE, HEADER_BLOCK  from dba_segments where segment_name in ('T_PART','T_P1','T_P2') and wner='SYS';

 

SEGMENT_NA PARTITION_NAME       SEGMENT_TYPE       HEADER_FILE HEADER_BLOCK

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

T_PART     T_P1                 TABLE PARTITION             1        62377

T_PART     T_P2                 TABLE PARTITION              1        62385

 

 

标注红色的部分,均发生了变化。为了明显的看出变化,我们使用下面数据表进行说明。

 

 

Before Exchange Operation

After Exchange Operation

obj_id

da_obj

file

block

obj_id

da_obj

file

block

t_part1

54439

54439

1

62377

54439

54442

1

62393

t_part2

54440

54440

1

62389

54440

54443

1

62401

t_part

54441

 

 

 

54441

 

 

 

t_p1

54442

54442

1

62393

54442

54439

1

62377

t_p2

54443

54443

1

62401

54443

54440

1

62389

 

3、 结论

 

经过上面数据表,我们已经很清晰的发现Oracle使用exchange partition的过程方法。在使用exchange partition的时候,Oracle并没有将替换数据表的数据复制到分区中,而是进行了一系列段元数据替换的操作。

 

Oracle将原有的数据表、分区物理段结构拆开,赋予一个新的逻辑名称object_id,更新原有的数据信息。这样,就在没有真正移动数据表数据的情况下,进行了数据的“乾坤挪移”。原来的数据表段,变成了分区段。而分区段变成了数据表段。

 

元数据中的object_id,是统一对外逻辑编号。为了维持逻辑上对象还是原来的对象,要保证这个对象取值的一致性。

 

exchange partition操作的优点也就不难想象。如果是单纯的复制,那么消耗的空间是进行分区移植数据的两倍,同时转移效率会随着分区中包括的数据量的大小而发生变化。exchange partition很类似truncate table,本质上是对段对象的DDL操作,保证只需要一份数据就可以加入到分区中。而且,当海量数据处理时,效率要远远高于复制操作。