移动分区时如何避免重建Oracle全局索引

时间:2016-02-09 12:45:18

标签: oracle indexing database-partitioning

我需要定期从一个表中分离分区并附加到不同表空间中的另一个表。

伪流:

  • 循环每个表和过期的分区:

    1.1在目标表中创建一个新的目标分区

    1.2将分区移动到目标表空间

    1.3将源分区交换到临时表

    1.4使用目标分区的交换临时表

    1.5 Drop source partition

  • 在源表中重建全局索引

  • 在目标表中重建全局索引

问题是,重建索引使索引临时不可用,在我的情况下支持实时应用是不可接受的。

索引重建是一项昂贵的操作,避免这种情况的一种方法是强制执行异步全局索引维护,这会使全局索引孤立,但仍然可以在不进行任何重建的情况下使用。但是,只能在Partition Drop和Partition Truncate操作中启用孤立索引。在上面的流程中,全局索引在分区移动和分区Exchange操作中呈现为不可用。最后一个语句中的分区删除不再能强制执行孤立索引。

这是令人费解的,因为我知道分区最终会被删除,但我仍然不得不重建全局索引。你能否建议避免索引重建?

注意:

  • 我可以在Partition Move和中使用UPDATE GLOBAL INDEXES子句 分区交换条款,但它是昂贵的,它会 在循环中多次调用。
  • 我可以将全局索引更改为本地索引,但这会有 对我们的应用产生更大的性能影此外,独特 index不起作用(不涉及分区键)。

1 个答案:

答案 0 :(得分:0)

一种可能的方法是在TMP表中复制要从ACT移动的分区(在所需的表空间中使用CTAS)而不是

  • 将TMP表与HIST表和
  • 的分区交换
  • 将分区放在ACT表中。

这种方法启用了异步全局索引维护,但不知何故,周点是移动分两步完成,因此理论上可能会有查询分区或没有分区(取决于两个步骤的顺序) 。如果这是一个问题,需要额外注意(例如锁定HIST表)。

这里使用INTERVAL PARTITONING的示例(表格设置如下)。

-- step 1 copy the partition to be moved from ACT table
create table tmp as 
select * from t_act partition FOR (TO_DATE('2016-02-21', 'YYYY-MM-DD'));

-- step 2 allocate partition in HIST table
LOCK TABLE t_hist
PARTITION FOR (TO_DATE('2016-02-21', 'YYYY-MM-DD'))
IN SHARE MODE;


-- step 3 publish the copy in HIST table and DROP the ACT partition
ALTER TABLE t_hist
EXCHANGE PARTITION FOR (TO_DATE('2016-02-21', 'YYYY-MM-DD'))
WITH TABLE tmp
INCLUDING INDEXES;

alter table t_act drop partition FOR (TO_DATE('2016-02-21', 'YYYY-MM-DD')) UPDATE INDEXES;

表格设置

drop  TABLE t_act;
CREATE TABLE t_act 
 (id number,
 transaction_date DATE not null,
  vc_pad VARCHAR2(100)
  )
 PARTITION BY RANGE (transaction_date)
 INTERVAL (NUMTODSINTERVAL(1,'DAY'))
  (
  PARTITION P_01  VALUES LESS THAN (TO_DATE('2016-02-22', 'YYYY-MM-DD') ),
  PARTITION P_02  VALUES LESS THAN (TO_DATE('2016-02-23', 'YYYY-MM-DD') )
  );

ALTER TABLE t_act ADD CONSTRAINT t_act_pk PRIMARY KEY (id);  
create index  t_act_ix1 on t_act(transaction_date); 

drop TABLE t_hist;
CREATE TABLE t_hist 
 (id number,
 transaction_date DATE not null,
  vc_pad VARCHAR2(100)
  )
 PARTITION BY RANGE (transaction_date)
 INTERVAL (NUMTODSINTERVAL(1,'DAY'))
  (
  PARTITION P_01  VALUES LESS THAN (TO_DATE('2016-02-20', 'YYYY-MM-DD') ),
  PARTITION P_02  VALUES LESS THAN (TO_DATE('2016-02-21', 'YYYY-MM-DD') )
  );

insert into t_act
select rownum, TO_DATE('2016-02-21', 'YYYY-MM-DD') ,'TEST' from dual connect by level <= 100000;
commit;