Hi All,
In this post i am going to share about Oracle Performance Issue: The Fake Index Trap Virtual/Fake/Nosegment Indexes.
Even though these fake indexes are not physically present, they can still create problems if you forget about them later.
To demonstrate this issue, I'll first create a new tablespace in lab session:
create tablespace RACS_TS datafile '/u01/app/oracle/oradata/GGDB1/pdb1/RACS_TS.DBF' size 100M;
I’ll create and populate a table in this RACS_TS tablespace:
I'll insert some data to this table
insert into RACS_TS select rownum, 'RACS INFOTECH' from dual connect by level <=10000;
commit;
gather the status for thi table :
exec dbms_stats.gather_table_stats(ownname=>null, tabname=>'RACS_TS');
I’ll next create a Virtual/Fake index, using the NOSEGMENT option:
create index RACS_TS_id_i on RACS_TS(id) nosegment tablespace RACS_TS;
We note this Fake Index is NOT listed in either USER_INDEXES or USER_SEGMENTS:
select index_name, tablespace_name from user_indexes where table_name='RACS_TS';
SQL> select index_name, tablespace_name from user_indexes where table_name='RACS_TS';
no rows selected
SQL>
If we run a basic, highly selective query on this table:
select * from RACS_TS where id=42;
We notice the CBO uses a FTS. The Fake Index is NOT considered by default.
However, if we set the session as follows and re-run the query:
alter session set "_use_nosegment_indexes" = true;
select * from RACS_TS where id=43;
Execution Plan----------------------------------------------------------Plan hash value: 43368621--------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU) | Time |--------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | 16 | 11 (0) | 00:00:01 ||* 1 | TABLE ACCESS FULL | RACS_TEST | 1 | 16 | 11 (0) | 00:00:01 |--------------------------------------------------------------------------------Predicate Information (identified by operation id):--------------------------------------------------- 1 - filter("ID"=43)Statistics---------------------------------------------------------- 0 recursive calls 0 db block gets 38 consistent gets 0 physical reads 0 redo size 648 bytes sent via SQL*Net to client 52 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processedWe can see the CBO appears to now use the Fake Index, but as it doesn’t actually physically exist, actually uses a FTS behind the scenes (the number of consistent gets is evidence of this). But at least we now know the CBO would at least consider such an index if it physically existed.
We now decide to drop the tablespace and so first try to MOVE the table to another tablespace using the ONLINE option:
alter table RACS_TS move online tablespace users;
We try to move the table using the default OFFLINE method:
alter table RACS_TS move tablespace users;
We have now successfully moved the table to another tablespace.
If we check to see if we have any other segments within the tablespace to be dropped:
select segment_name from dba_segments where tablespace_name='RACS_TS';
Oracle tells us that no, we do NOT have any current segments in this tablespace.
So it’s now safe to purge and drop this tablespace (or so we think):
purge tablespace RACS_TS;
drop tablespace RACS_TS;
The tablespace has been successfully dropped.
However, if we now re-run the query on this table:
select * from RACS_TS where id=43;
We get this unexpected error that the tablespace RACS_TS does not exist.
BUT, we already know the tablespace doesn’t exist, we’ve just dropped it !!!
So why are we getting this error?
It’s all due to the damn Fake Index we created previously.
Although there is no physical index segment for our Fake Index, there are still some internal Data Dictionary links between the Fake Index and the tablespace it was associated with. The tablespace is gone, but NOT the Fake Index.
The only place where fake indexes can be easily found within Oracle, is within the USER_OBJECTS view:
select o.object_name, o.object_type, o.status from user_objects o left join user_indexes i on o.object_name=i.index_name where o.object_type='INDEX' and i.index_name is null;
To eliminate this error, we have to first drop the Fake Index associated with the dropped tablespace:
drop index RACS_TS_id_i;
We can now safely run the query without error:
select * from RACS_TS where id=43;
So if you do ever create Fake Indexes, don’t forget to drop them once you’ve finished experimenting with them.
if you ever decide to drop the tablespace into which they were associated. This is explained in part in Oracle Support Doc ID 1361049.1.
Thanks,
Srini