日期:2014-05-16  浏览次数:20511 次

Oracle分区表的分区交互技术实现数据快速转移

有一个需求,将某业务表的某个时间点之前的记录转移到它的历史表中。如果当前业务表不是基于这个业务时间点的分区表设置,那只能insert再delete操作。这种转移数据的方法非常非常低基础。经常在初级的数据库管理人员和开发人员的程序中出现。不是说这个方法不好,对于转移的记录数量在几十几百条,而转移频率高,转移时间点随机的情况而言,这个方法还是挺管用的。但如果转移的数据量一次数以百万计的话,这种方法就显得低效了。
因此,在Oracle数据库开发中,对于这种大数据的转移可以使用分区表交换技术实现。即使你一次转移的数据量几亿甚至几十亿也没有关系,转移时间依然是毫秒级的。这个方法大体流程是这样:
首先,你需要将当前表修改为分区表,找到分区字段很关键;其次,这个分区表的索引都建立成本地索引,全局索引就不要了,原因后面介绍;再次,建立一个对应的临时非分区表,表结构和这个一样;最后使用alter table table_name exchange partition? Partition_name with table table_name_exchange;操作,将表分区所拥有数据的实际物理存储空间段相互交换,这是指针级的操作。
这样就完成了这个表分区数据的快速转移。

就这个操作流程,做一个测试。

?

(miki西游 @mikixiyou 原文链接: http://mikixiyou.iteye.com/blog/1773659)

第一步,准备环境

建立一张测试表SALE,它的分区字段是DOTIME,按照季度进行分区。

CREATE TABLE SALE
(
  DOTIME          DATE                          DEFAULT sysdate,
  BILLID          VARCHAR2(20 BYTE)             NOT NULL,
  FROMARREAR      NUMBER(16,4)                  DEFAULT 0
)
PARTITION BY RANGE (DOTIME)
( 
  PARTITION PY11Q3 VALUES LESS THAN (TO_DATE(' 2011-10-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
    LOGGING, 
  PARTITION PY11Q4 VALUES LESS THAN (TO_DATE(' 2012-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
    LOGGING, 
  PARTITION PY12Q1 VALUES LESS THAN (TO_DATE(' 2012-04-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
    LOGGING, 
  PARTITION PY12Q2 VALUES LESS THAN (TO_DATE(' 2012-07-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
    LOGGING, 
  PARTITION P_MAX VALUES LESS THAN (MAXVALUE)
    LOGGING
)
;

?

再建立一张交换表,表的字段结构和分区表完全一致。

create table SALE_exchange
(
  DOTIME          DATE                          DEFAULT sysdate,
  BILLID          VARCHAR2(20 BYTE)             NOT NULL,
  FROMARREAR      NUMBER(16,4)                  DEFAULT 0
);

?

注意,分区表上的主键所属的全局唯一索引不要了,改成SALE (BILLID,DOTIME)上的本地索引,这样也能保证数据的一致性。原来的主键字段billid必须放在前面,防止原来原来基于billid直接查询操作的性能下降太多。

create unique index PK_SALE on SALE (BILLID,DOTIME) local;

本地分区索引创建完毕。


第二步,
检查一下数据记录情况。假设我们要将PY11Q3分区中的记录转移走。
select count(*) from SALE partition(PY11Q3);
select? count(*)? from SALE_exchange;

第三步,转移数据

alter table SALE exchange partition? PY11Q3 with table SALE_exchange;

一个命令,将分区段和表段的空间指针互相替换,就实现了这个分区表的业务数据的转移工作。

第四步,检查索引状态

分区表这点不好,如果分区发生改变,如exchange,move,split等,那么该分区上的本地索引分区就会失效,同时整个分区表上的全局索引也会失效。所以我最开始说全局索引需要撤销了,就是这个道理。试想,如果这时还有全局索引存在,那它失效了,这就将影响到分区表的其他业务操作。

不管怎样,都需要检查一下索引状态。

select index_name, partition_name, status
  from user_ind_partitions
 where status = 'UNUSABLE'
union all
select index_name, '' as partition_name, status
  from user_indexes
 where status = 'UNUSABLE';

?

这里,本地分区索引的索引分区肯定失效了。原来exchange表上的索引也会失效。它们都需要重建。
分区索引的重建:
alter index PK_SALE rebuild partition PY11Q3;
?
alter index PK_SALE_EXCHANGE rebuild;


经过这样的操作之后,历史数据是从当前业务表移出来了,但它在一个临时的孤立的表中。在现实业务中,这样的数据是需要移动历史表中。当然,如果你有转换操作,你可以继续使用insert 方法转移。如果没有,你还可以使用分区交换技术,将这个数据交换到历史表中。

简而言之,Oracle分区表技术在大数据量表的操作中建议经常使用,它的很多特性有助于我们开发出高效的应用程序。