上篇我们讨论了unusable的原理和使用,设置为unusable的索引,连带的DML操作会如何呢?
注意下面的实验,笔者发现,如果此时对数据表进行DML操作,数据库会报错拒绝。
SQL> insert into stktestonhand (SEQ_NUMBER, FORMCODE, SERIESNUMBER_FROM, SERIESNUMBER_TO, TICKET_QUANTITY, REASONCODE_SEQ, CREATE_USER, CREATE_DATE, ALLOCATION_DATE)
2 values (0,'000','100000000','1200000',32,43,'TEST',sysdate,sysdate);
insert into stktestonhand (SEQ_NUMBER, FORMCODE, SERIESNUMBER_FROM, SERIESNUMBER_TO, TICKET_QUANTITY, REASONCODE_SEQ, CREATE_USER, CREATE_DATE, ALLOCATION_DATE)
values (0,'000','100000000','1200000',32,43,'TEST',sysdate,sysdate)
ORA-01502: 索引 'NBSTEST.IND_STKTESTONHAND_COMP0' 或这类索引的分区处于不可用状态
这部分和我们原来对于unusable的理解存在差异,这个问题我们暂时留待下面解决。如果要恢复索引,需要重建对象。
SQL> alter index IND_STKTESTONHAND_COMP0 rebuild
2 ;
Executed in 0.609 seconds
SQL> select index_name, table_name,UNIQUENESS,status, num_rows, VISIBILITY from user_indexes where index_name='IND_STKTESTONHAND_COMP0';
INDEX_NAME TABLE_NAME UNIQUENESS STATUS NUM_ROWS VISIBILITY
-------------------- --------------- ---------- -------- ---------- ----------
IND_STKTESTONHAND_CO STKTESTONHAND UNIQUE VALID 200100 VISIBLE
MP0
下面我们实验invisible特性。
SQL> alter index ind_stktestonhand_comp0 invisible;
Executed in 0 seconds
SQL> select index_name, table_name,UNIQUENESS,status, num_rows, VISIBILITY from user_indexes where index_name='IND_STKTESTONHAND_COMP0';
INDEX_NAME TABLE_NAME UNIQUENESS STATUS NUM_ROWS VISIBILITY
-------------------- --------------- ---------- -------- ---------- ----------
IND_STKTESTONHAND_CO STKTESTONHAND UNIQUE VALID 200100 INVISIBLE
MP0
Executed in 0.062 seconds
此时,我们使用原有的SQL语句进行检索。
SQL> explain plan for select * from stktestonhand where SERIESNUMBER_FROM<=lpad('10000',10,'0') and SERIESNUMBER_TO>=lpad('10000',10,'0');
Executed in 0 seconds
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------
Plan hash value: 2311662756
-------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 183 | 11346 | 588 (2)| 00:00:0
|* 1 | TABLE ACCESS FULL| STKTESTONHAND | 183 | 11346 | 588 (2)| 00:00:0
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("SERIESNUMBER_FROM"<='0000010000' AND
"SERIESNUMBER_TO">='0000010000')
Executed in 0.141 seconds
同unusable一样,当索引被设置为invisible之后,Oracle优化器在生成执行计划的时候,是不会选择索引路径的。那么,invisible的索引是否和数据表还保持的DML同步呢?
SQL> insert into stktestonhand (SEQ_NUMBER, FORMCODE, SERIESNUMBER_FROM, SERIESNUMBER_TO, TICKET_QUANTITY, REASONCODE_SEQ, CREATE_USER, CREATE_DATE, ALLOCATION_DATE)
2 values (0,'000','100000000','1200000',32,43,'TEST',sysdate,sysdate)
3 ;
Executed in 0 seconds //对invisible索引的对象,是允许插入数据的。
(调用专门脚本,添加数据…)
SQL> select count(*) from stktestonhand;
COUNT(*)
----------
300100 //从原来的20万行,增加到30万
Executed in 0.047 seconds
SQL> select segment_name, segment_type,bytes,blocks from user_segments where segment_name='IND_STKTESTONHAND_COMP0';
SEGMENT_NAME SEGMENT_TYPE BYTES BLOCKS
--------------- ------------------ ---------- ----------
IND_STKTESTONHA INDEX 11534336 1408
ND_COMP0
Executed in 0.031 seconds
我们数据量从原来的20万增加到30万,同时索引对象的体积也变化到了11MB。说明,即使索引被invisible,不参与执行计划生成,但是会随着源数据表的DML操作而同步。
到此,我们得到了结论:invisible属性的作用就是让索引对象不参与进Oracle优化器执行计划生成过程,但是会随着数据表DML操作而更新。这点是与unusable的最大区别!
恢复属性,执行下面语句。
SQL> alter index ind_stktestonhand_comp0 visible;
Executed in 0.015 seconds
反思:站在Oracle的角度,想下为什么Oracle要提供这个invisible功能。如果没有这个属性,当我们需要暂时性的取消索引(调试、系统整理和实验),只能够删除索引或者unusable索引,让索引完全失效。这样虽然可以实现失效目的,但是带来一定的性能问题。
如果需要索引重新应用,相当于重建rebuild索引对象。我们反复说过,索引是一种有负担的对象,对一些海量数据表,重建数据表是很消耗时间和资源的,而且还伴随着一系列的锁操作。这对一些OLTP系统,特别是业务高峰期的系统,这种风险是不能轻易承受的。
invisible的出现,主要还是Oracle11g中对online特性支持的一种体现。索引虽然被invisible不可见了,但是只是一个标志的问题,索引本身还会和数据表维持联系。这样,进行索引失效切换动作,也会更加平滑安全。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/17203031/viewspace-688136/ ,如需转载,请注明出处,否则将追究法律责任。