删除分区如何不让全局索引失效?

记得上次ACOUG年会(《ACOUG年会感想》),请教杨长老问题的时候,谈到分区,如果执行分区删除的操作,就会导致全局索引失效,除了使用12c以上版本能避免这个问题外,指出另外一种解决的方式,表面看很巧妙,实则是对分区原理的深入理解。

我们先从实验,了解这个问题,首先创建分区表,他存在4个分区,每个分区中,都存在数据,

SQL> CREATE TABLE interval_sale
  2  ( prod_id        NUMBER(6)
  3  , cust_id        NUMBER
  4  , time_id        DATE
  5  )
  6  PARTITION BY RANGE (time_id)
  7  INTERVAL(NUMTOYMINTERVAL(1, 'YEAR'))
  8    ( PARTITION p0 VALUES LESS THAN (TO_DATE('1-1-2003', 'DD-MM-YYYY')),
  9      PARTITION p1 VALUES LESS THAN (TO_DATE('1-1-2004', 'DD-MM-YYYY')),
 10      PARTITION p2 VALUES LESS THAN (TO_DATE('1-1-2005', 'DD-MM-YYYY')),
 11      PARTITION p3 VALUES LESS THAN (TO_DATE('1-1-2006', 'DD-MM-YYYY')));

SQL> insert into interval_sale values(1, 1, to_date('2002-01-01','yyyy-mm-dd'));
1 row created.

SQL> insert into interval_sale values(2, 2, to_date('2003-01-01','yyyy-mm-dd'));
1 row created.

SQL> insert into interval_sale values(3, 3, to_date('2004-01-01','yyyy-mm-dd'));
1 row created.

SQL> insert into interval_sale values(4, 4, to_date('2005-01-01','yyyy-mm-dd'));
1 row created.

SQL> commit;
Commit complete.

创建全局索引,当前状态是VALID,

SQL> create index idx_01 on interval_sale(cust_id);
Index created.

SQL> select table_name, index_name, partitioned, status
  2  from user_indexes where table_name='INTERVAL_SALE';
TABLE_NAME       INDEX_NAME      PARTITIONED  STATUS
--------------- --------------- ------------ --------
INTERVAL_SALE    IDX_01          NO           VALID
删除第一个分区,
SQL> alter table interval_sale drop partition for (to_date('2002-01-01','yyyy-mm-dd'));
Table altered.

此时,看到这个全局索引是UNUSABLE的状态,和我们的设想是相同的,即删除分区,会导致全局索引的失效,

SQL> select table_name, index_name, status
  2  from user_indexes where table_name='INTERVAL_SALE';
TABLE_NAME       INDEX_NAME      STATUS
--------------- --------------- ----------
INTERVAL_SALE    IDX_01          UNUSABLE

结论告诉我们,删除分区,确实会导致全局索引的失效,我们从问题入手,为什么分区删除,会导致全局索引的失效?

我们知道,Oracle中索引是以B树的结构存储的,包括了索引键值、rowid信息,而且按照索引键值有序排列,当通过索引扫描需要回表的时候,能利用rowid直接定位到索引键值对应的数据块,这是最快的数据访问方式。当我们删除表中数据的时候,同时要删除他对应的索引,由于索引是有序排列的,如果要删除一条索引数据,他的组织结构,就需要调整,以保证正确的排列顺序,12c之前,因为某种原因,无法在删除分区的同时,对索引重新构建,所以此时索引的状态是失效的,与其是错的,宁可不让用,删除分区,需要手工rebuild重建索引才能让其生效,

我们换种思路,之所以全局索引的状态失效,根本问题就是索引对应的分区中数据被删除了,那么,如果不删除分区中的数据,索引结构无需任何调整,他的状态是不是就是正常的?

首先重建索引,让其生效,

SQL> alter index idx_01 rebuild online;
Index altered.

SQL> select table_name, index_name, status
  2  from user_indexes where table_name='INTERVAL_SALE';
TABLE_NAME       INDEX_NAME      STATUS
--------------- --------------- --------
INTERVAL_SALE    IDX_01          VALID

此时,通过delete删除即将删除的第二个分区的数据,

SQL> delete from interval_sale where time_id <= to_date('2003-01-01','yyyy-mm-dd');
1 row deleted.

SQL> commit;
Commit complete.

再次执行分区删除的操作,

SQL> alter table interval_sale drop partition for (to_date('2003-01-01','yyyy-mm-dd'));
Table altered.

此时,再看全局索引,他的状态正常,VALID,并未因为分区删除的操作,导致其失效,

SQL> select table_name, index_name, status
  2  from user_indexes where table_name='INTERVAL_SALE';
TABLE_NAME       INDEX_NAME      STATUS
--------------- --------------- --------
INTERVAL_SALE    IDX_01          VALID

通过以上实验,可以得到结论,如果待删除的分区中没有任何数据,执行分区删除,不会导致全局索引状态的失效。原因已经说了,因为分区删除时,不存在任何数据需要删除,意味着无需调整索引结构,所以全局索引的状态,就无需置为失效,这个算是对待分区删除避免全局索引失效的一种另类解决方案了。

通过这个问题,能让我体会到的,就是一个看着很简单的问题背后,其实蕴涵着丰富的知识,同时对待任何一个知识点,从原理层理解地越深入,找到问题的本质,就可以让你和真相更近,豁然开朗,这可能就需要日常的积累,碰到问题的时候,多问一句为什么,就可能让你大开眼界,这就是Oracle以及技术领域最吸引人的地方了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值