上周五意外发现一个分区表的全局索引失效变为unusable,在监控SQL性能时有几个SQL因为这个索引而挂掉。
忽然想起是前一天进行测试时,对该表一个分区做了exchange交换分区操作。下面还原下场景:
create table test(id number,name varchar2(10))
partition by list(id)
(
partition p1 values(1),
partition p2 values(2),
partition p3 values(3)
);
create index idx_test_id on test(id);--全局索引
create index idx_test_name on test(name) local;--本地索引
SQL> select table_name,index_name,status from user_indexes where table_name='TEST';
TABLE_NAME INDEX_NAME STATUS
------------------------------ ------------------------------ --------
TEST IDX_TEST_NAME N/A
TEST IDX_TEST_ID VALID
N/A表示是本地索引状态,VALID是全局索引状态。
1.交换分区(此时表中无数据)
SQL> create table t as select * from test;
表已创建。
SQL> alter table test exchange partition p1 with table t;
表已更改。
SQL> select table_name,index_name,status from user_indexes where table_name='TEST';
TABLE_NAME INDEX_NAME STATUS
------------------------------ ------------------------------ --------
TEST IDX_TEST_NAME N/A
TEST IDX_TEST_ID UNUSABLE
可以看到此时全局索引由valid变为unusable,本地索引状态没有变。
2.truncate分区
首先将全局索引重建:
alter index idx_test_id rebuild;
此时查看
SQL> select table_name,index_name,status from user_indexes where table_name='TEST';
TABLE_NAME INDEX_NAME STATUS
------------------------------ ------------------------------ --------
TEST IDX_TEST_NAME N/A
TEST IDX_TEST_ID VALID
直接truncate分区看看,
SQL> alter table test truncate partition p1;
表被截断。
SQL> select table_name,index_name,status from user_indexes where table_name='TEST';
TABLE_NAME INDEX_NAME STATUS
------------------------------ ------------------------------ --------
TEST IDX_TEST_NAME N/A
TEST IDX_TEST_ID VALID
直接truncate没有数据的分区p1,全局分区和本地分区索引状态都不变。
SQL> insert into test values(1,'a');
已创建 1 行。
SQL> alter table test truncate partition p1;
表被截断。
SQL> select table_name,index_name,status from user_indexes where table_name='TEST';
TABLE_NAME INDEX_NAME STATUS
------------------------------ ------------------------------ --------
TEST IDX_TEST_NAME N/A
TEST IDX_TEST_ID UNUSABLE
在p1分区插入数据后,再执行truncate分区,这时发现本地分区状态没有变,但是全局分区状态由valid变为unusable。
3.drop分区
首先将全局索引重建:alter index idx_test_id rebuild;
SQL> select table_name,index_name,status from user_indexes where table_name='TEST';
TABLE_NAME INDEX_NAME STATUS
------------------------------ ------------------------------ --------
TEST IDX_TEST_NAME N/A
TEST IDX_TEST_ID VALID
SQL> alter table test drop partition p1;
表已更改。
SQL> select table_name,index_name,status from user_indexes where table_name='TEST';
TABLE_NAME INDEX_NAME STATUS
------------------------------ ------------------------------ --------
TEST IDX_TEST_NAME N/A
TEST IDX_TEST_ID VALID
分区中没有数据时,执行drop分区不会影响全局索引状态。
SQL> insert into test values(2,'a');
已创建 1 行。
SQL> alter table test drop partition p2;
表已更改。
SQL> select table_name,index_name,status from user_indexes where table_name='TEST';
TABLE_NAME INDEX_NAME STATUS
------------------------------ ------------------------------ --------
TEST IDX_TEST_NAME N/A
TEST IDX_TEST_ID UNUSABLE
分区中有数据时执行drop分区,会改变全局索引状态。
而我们知道,全局索引和本地索引执行dml都不会改变索引状态;
但是从上面得知,在进行交换分区时会改变全局索引状态;当drop或truncate分区并且分区里有数据时,会改变全局索引状态。
但是他们都不改变本地索引状态。
有时你可能会忽然发现全局索引失效,其实这对于生产库来说是很可怕的事情。在操作时千万要小心,如果不得不进行会引起全局索引失效的操作,
那么操作完毕一定要记得将全局索引rebuild。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/24496749/viewspace-734921/ ,如需转载,请注明出处,否则将追究法律责任。