Unused indexes

create table big( id number, name varchar2(100));
insert into big(id, name) select rownum, object_name from all_objects;
create index big_index on big(id);






select count(*) from big;
1260398 




1.EXPLAIN PLAN FOR  
SELECT   ID  FROM big ORDER BY id; 


SELECT *  FROM TABLE(DBMS_XPLAN.DISPLAY); 


Plan hash value: 1222949096

-----------------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |  1260K|  7385K|       |  5549   (2)| 00:01:07 |
|   1 |  SORT ORDER BY     |      |  1260K|  7385K|    14M|  5549   (2)| 00:01:07 |
|   2 |   TABLE ACCESS FULL| BIG  |  1260K|  7385K|       |  1444   (1)| 00:00:18 |
-----------------------------------------------------------------------------------




2. EXPLAIN PLAN FOR  
SELECT   *  FROM big ORDER BY id; 
Plan hash value: 1222949096

-----------------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |  1260K|    30M|       | 10550   (1)| 00:02:07 |
|   1 |  SORT ORDER BY     |      |  1260K|    30M|    43M| 10550   (1)| 00:02:07 |
|   2 |   TABLE ACCESS FULL| BIG  |  1260K|    30M|       |  1445   (1)| 00:00:18 |
-----------------------------------------------------------------------------------




In why does the time increases to 2:07 for the second explain plan

Why the time increases to 02:07 for the second plan to explain?

Hello

1. in comparing Oracle index as an index of a book where the index can occupy a few pages, how store Oracle index?

Oracle stores the index "outside of work". The index has also usually occupies less space than the table. (that's why I suggested to create your table of test with more fields to better see the difference. You can take a look at Where USER_SEGMENTS to see the size of the table and the size of the index)

2. why the column must be NON NULL for indexes to use?

Because the null entries are not stored in an index, if Oracle does not know that there may be NULL values, it can "use the index to be sure to find ALL values... Imagine a table T (col1 NUMBER, VARCHAR2(10 CHAR) NOT NULL, col2, col3,...) where col1 is NOT defined as "not null", and the table contains three lines:

(10, 'x',...), (NULL, 'y',...) and (2, 'z',...)  and there is an index on col1 and col2 on.

If asked "SELECT col1 FROM t", Oracle must retrieve three lines: 10, NULL, 2. search in the index would show only 2 and 10 but not NULL... But if we ask "SELECT col2 FROM t" then Oracle can use the index on col2 because he knows "design table" who will miss us no line. If the dictionary contains more information (columns not null, unique constraints, primary key, foreign key) this info can be used by the optimizer. In addition, the optimizer can make best estimates when accurate statistics are available (statistics include things like "distinct values how we have for the column?) How many rows have a NULL value? What are the minimum and maximum values of the column? ... "- Note that via statistical table, knowing that there are values null null to a column is not the same thing that to know this fact via a NOT NULL constraint present in the dictionary... If the optimizer has only information through statistics, this cannot be used to decide"we will use the index"as it is possible that, despite the news of the stats it is possible that NULL values exist (created after the last update of stats or) failure by the updating of statistics due to the sample data used to update statistics).

Providing constraints (not null, unique, pk, fk, check) for the dictionary is not only good for the optimizer but also good to add quality control of data do not believe developers/suppliers of applications that tell you that the constraints are unnecessary, as the design of the application supports controls ;-)

Best regards

Bruno Vroman.

Tags: Database

Similar Questions

  • What causes this "cleaning 12 entered unused index file 0 $SII x 9.

    Why always do following the briefing note on "unused index entries" Winlogon in respect of the Application in my event viewer when I do a Check Disk?

    Also, I play a 'chkdsk /f"if I run Chkdsk by going to Windows Explorer, right-click on my hard drive, choosing Properties, tools, error checking, check now and the two options?  (He still plans on the next reboot.)

    __________________________________________

    Checking file system on C:
    The type of the file system is NTFS.
    Volume label is SQ004207P01.

    A disk check has been programmed.
    Windows will now check the disk.
    Cleaning 12 entered unused index file 0 $SII x 9.
    Cleaning 12 entered unused index file 0 $SDH x 9.
    Cleaning of security descriptors not used 12
    .
    CHKDSK checks Usn Journal...
    Audit of the USN Journal is complete.
    CHKDSK is verifying file data (stage 4 of 5)...
    File data verification completed.
    CHKDSK is verifying free space (step 5 of 5)...
    Free space verification is complete.

    77834893 KB total disk space.
    13842992 KB in 48756 files.
    16080 Ko 5274 index.
    0 KB in bad sectors.
    147953 KB used by the system.
    65536 KB occupied by the log file.
    63827868 KB available on disk.

    4 096 bytes in each allocation unit.
    19458723 total allocation on the drive units.
    15956967 allocation units available on disk.

    Internal information:
    D3 1 00 d 01 1 a 00 00 and 00 c6 01 00 00 00 00 00 1B...
    D4 02 00 00 03 00 00 00 7 b 06 00 00 00 00 00 00... {.......
    5A 16 04 00 00 00 00 19 81 1 c0 c7 d 00 00 00 00 Z...
    32 40 93 0e 00 00 00 00 c8 f9 7 c 00 02 00 00 00 2@...| .....
    3rd DF 04 06 00 00 00 26 56 97 8 a 04 08 00 00 00... & V. >...
    9F 99 36 00 00 00 00 00 88 38 07 00 74 be 00 00... 6... 8.t...
    00 00 00 00 00 03 00 00 00 9 a 14 00 00 4 c e8 c0... L........

    Windows has finished checking your disk.
    Please wait while your computer restarts.

    For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.

    I googled them and the search results seemed to suggest there was some kind of security threat.  At that time, the number was significantly higher at 12.  (in the 80 years and 50 years.)  I thought that maybe the words 'security descriptors' should I worry.

    No, it isn't really a threat.  Security descriptors are where permissions are stored, these permissions to control who can and who have no access to 'the object' in question.  Unused security descriptors simply means that descriptors that are not used.  Files can no longer be present or the descriptor can be orphaned otherwise, like everything is blank and the error message can be annoying to see but in your case, it's nothing to worry about.

    What are the security and access control lists descriptors?

    John

  • Unused indexes in PS CVDDH ACCTG LINE... remove them?

    There are a number of table index SQL Server comes with table PS_VCHR_ACCTG_LINE who appear to have no. seeks, scans or searches and some clues that have only a few 10 similar. These indices take much space. In total, they are half of the disk space used for this table. Looks like it would be good to remove these and re - use this space. Maybe with some other indexes even better.
    More precisely:

    Not looking, analyses, research:

    PSCVCHR_ACCTG_LINE
    PSEVCHR_ACCTG_LINE
    PSGVCHR_ACCTG_LINE
    PSJVCHR_ACCTG_LINE

    Rare:
    PSHVCHR_ACCTG_LINE
    PSKVCHR_ACCTG_LINE

    No matter who else looked or done this? Why are they here? If only they were supposed to be removed when others have been added?

    PeopleSoft Financials 9.1, 8.52 tools.

    Ron

    You can remove, but it would be considered a customization. Some clues have comments associated with them that should give you an idea what they are for. According to the features of your users are using currently, you can always wait you will have unused indexes on the tables though. Disk is cheap, however, so customize to save space probably is not worth.

    You can view comments in the application designer, or use SQL - something like

    Select indexid, idxcomments from psindexdefn where recname = "VCHR_ACCTG_LINE" to order by indexid;

    If you do not want to drop an index, you must set the platform to zero indicator (not active) in the application designer (Tools-> Data Administration-> index, then highlight the index you want to delete and click on modify indexes). If you use Build-> current definition and select Create indexes (make sure you build settings say create the indexes only if change), I think it will generate the DROP INDEX instructions for you.

    If you remove just the index in Oracle, you will get errors DDDAUDIT. If you completely delete the index definition in the application designer, it will probably not be identified as a customization in an upgrade and the index will reappear if you aren't careful.

    Kind regards

    Bob

  • Oracle 10.2.0.3.0 - impdp - unusable index exists on unique/primary...

    Hi all

    Oracle 10.2.0.3.0 - during impdp the following error appears:

    Object type SCHEMA_EXPORT/TABLE/CONSTRAINT/treatment
    ORA-39083: THAT CONSTRAINT Type could not create object error:
    ORA-14063: unusable Index exists on constraint unique/primary key
    Because sql is:
    ALTER TABLE 'MY_SCHEMA '. "' MY_TABLE ' ADD CONSTRAINT PRIMARY KEY 'MY_TABLE_PK' ('ID')
    USING INDEX PCTFREE, INITRANS 10 2 MAXTRANS 255
    STORAGE (INITIAL 1048576 THEN 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 DEFAULT USER_TABLES)
    TABLESPACE "MY_TBS".

    Question:

    Tree index does not contain the dump file, and impdp should simply create index as it appears in the metadata information.

    So, what's the point to clear this error?

    921817 wrote:

    So, what's the point impdp tells his State? It can be hundreds of unusable indexes, why it is not only rebuild?

    Because Impdb cannot create an object that is already there and can't make it valid.

    Aman...

  • Skip unusable indexes - true assigned to the parameter true but always get error if unusable pk

    Hello

    Using 11.2.0.3 and when moving data in a partitioned table (Beach dates then Sub partitioned on hash) to another constraint of pk tablespace on table that uses (global) indexes marked as UNUSABLE.

    Other indices also marked as UNUSABLE, but considers that the need to rebuild the inserts if not later PK index in the table fail.

    Sounds like the setting index skip unusable applies to all indexes apart form PK index which must always be used.

    This interpretation is correct?

    Thank you

    Yes

  • Unusable index Partitioned table

    Oracle Version: 11.2.0.2
    OS: Linux RHEL 5

    I'm having a problem with the index on a partitioned table interval. This is the scenario:

    There are 3 indices (A, B, C) on a table. A is created on two columns (1,2), B is on the column (2), C is the column (3). Table is partitioned on column 2 apart. A and B are partitioned indexes. When I drop a partition without a clause to update index, Index C will unusable. After seeing this, I gave up the C rating and create it as a local partitioned index, then all indexes are in condition of use after the drop partition statement. Is - this mandatory on a range partitioned table all indexes on the table must be locally partitioned inorder to have indexes in usable state after the drop statement of partition (without the update index clause)? Also there will be a negative impact for all indexes on the table like locally partitioned indexes?

    >
    Is - this mandatory on a range partitioned table all indexes on the table must be locally partitioned inorder to have indexes in usable state after the drop statement of partition (without the update index clause)?
    >
    Yes - it should be obvious by looking at a simple example.

    You have an OVERALL index and drop a partition but say Oracle are NOT updating the overall index.

    How this index may be usable for anything? It is not accurate. There was GARBAGE everywhere that gets in the way of Oracle find the entries of the "good". There are the index keys in the branch blocks that belong to the partition that has been deleted. Oracle cannot use these keys to determine how the blocks of branch, he needs to find.
    >
    Also there will be a negative impact for all indexes on the table like locally partitioned indexes?
    >
    Who knows? There are maybe or maybe not.

    As with many things Oracle "it depends."

    It depends on what types of queries that you ran.

    It depends on the filter predicates used for query.

    It depends on if the maintenance simple score (add/drop/split) are important to you.

    For the maintenance of the partition only all index LOCAL is the best.

    For full table scan, an index is not intended to be used.

    For a query that needs all THE records for a COMPANY_ID given in a table partitioned by DATE an OVERALL index could be better. Oracle also use 100 index LOCAL (if there are 100 partitions) to get the same data.

    It depends on.

  • Moving the partitions to tablespace diffreent marking unusable indexes

    Hello

    I use 11.2.0.3 oracle on IBM PoWER sERIES 7 ON aix

    and have a routine to move partitions greater n days in a dedicated tablespace, but when that move these old partitions of the index are marked as unusable.

    How can I avoid this, what am I doing wrong?
      execute immediate ('alter table '||i.table_name||' move partition '||i.partition_name
                                 ||' tablespace '||v_archive_partition_tspace);
    move works very well but the indexes show also unusable and not want to re-create the index each time that would take nearly an hour.

    Table partitioned by day_num (NUMBER)

    each partition belongs to the same tablespace BI_DATA and index belong to the BI_IDX.

    When moving the old question of partitions above the command - t - it not unlcude the index - thera is an index option?

    Thank you

    It is up to you; storage spaces are for administrative convenience.

    My preference would be to place them in a tablespace - you would never restore without the table index or vice versa, so put in a single tablespace would be convenient administratively.

  • Identification and drops the unused index - index of key foreign - 11g R2

    Hi team,

    In our application, table main source have nearly 55 M records and this table have almost 15 foreign key columns. He y 5 foreign key columns that reference 5 very small tables (max 10 lines for each table) where the child tables ever updated or removed, it's very static data.

    so we thought to remove the foreign key index, in order to expedite the DML operations on the source table.

    It's the right option... ?

    Please guide me on the right track, please...

    Thank you

    RAM

    Almosty certainly right, but there are a number of things to be wary of:

    (a) you can't update the keys to reference table (parent) deliberately, but some application codes (typically a form generated) can use a generic statement to update the line and include 'id of the game {its original value} =' as part of the update. It is always updated the parent key even if it does not change, and he closed the child table.

    (b) you have an example where 99.9999% of one of the columns has a single value and the other 0.0001% of the data is shared between the remaining values of 9 parent - this could be useful as a path index even if you do not need to protect against the problem of blocking foreign. In this case you need to constrauct a histogram on the column for that the optimizer can see the extreme data distribution.

    Options

    (a) If you are confident that the parent tables never see no DML so you can move them to a separate tablespace that you do read-only (older versions of Oracle) or make read-only tables (12 c)

    (b) you can disable locking on the child table - it always helps to have implicit mode 2 and mode 3 locks (which will not appear in the lock of v$), but stop a parent update to acquire mode 4 it would be necessary for the child if something tries to update or delete the parent key.  There are however some behavior buggy serious around this area, and I don't know if it was fixed yet: https://jonathanlewis.wordpress.com/2010/02/15/lock-horror/

    ADDENDUM: If almost all the data of a column contains the same, then you can consider using a null to represent this value. Otherwise, you could play with index based on a function (changing the code of the application accordingly) to create an index that contains only the values 'rare' rather than having an index that held an entry for each row in a table. This approach would also avoid the need for a histogram.  Something like the folllowing (although the example is not a perfect match for your requirement): https://jonathanlewis.wordpress.com/2014/04/02/tweaking/

    Concerning

    Jonathan Lewis

  • Search for unused index

    Dear administrators,

    I'll do a kind of cleansing for my database and I need to know the last 'use date' for each clue, so I can not get used.

    Is this possible?

    date of last of 'use' for each index

    No version of Oracle. You can identify the specific index is used or not from v$ object_usage.

    [Index monitoring | http://www.oracle-base.com/articles/10g/IndexMonitoring.php]

  • The index of the first State UNUSABLE.

    Hi my current version of the DB is version 11.2.0.3.0 Oracle.

    In one of the old environment (Release 10.2.0.4.0), I found one of the query works fine (about 4 minutes) while the same get expired (~ 30 minutes) in the current version(11g).

    After analysis found that in 10g environment its going for scan limited index, but 11g a its goes for FTS of the same table.
    Then I tried to force the flag for 11g environment and got below error.

    ERROR on line 1:
    ORA-01502: index 'INV_ID1' or partition of this index is unusable

    But when I tried to understand the usual State status, its display n/a, index partitioned index.
    I checked the status column of DBA_IND_PARTITION for all partitions 62 specific for the index INV_ID1, its display "n/a".
    So my question is how can I find the UNUSABLE State of this/other index in my database and repair?

    The index above is local partitioned with 62 partitions. Here is the comparison of the plan.
    10g:
    ------------------------------------------------------------------------------------------------------------------------------------------------------------
    | Id  | Operation                             | Name                 | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
    ------------------------------------------------------------------------------------------------------------------------------------------------------------
    |   1 |  TABLE ACCESS BY INDEX ROWID          | pi                   |      0 |      1 |      0 |00:00:00.01 |       0 |      0 |       |       |          |
    |*  2 |   INDEX UNIQUE SCAN                   | pi_PKI               |      0 |      1 |      0 |00:00:00.01 |       0 |      0 |       |       |          |
    |   3 |  SORT ORDER BY                        |                      |      1 |    500 |      0 |00:04:30.17 |   95321 |   4557 |  1024 |  1024 |          |
    |*  4 |   COUNT STOPKEY                       |                      |      1 |        |      0 |00:04:30.17 |   95321 |   4557 |       |       |          |
    |   5 |    PARTITION RANGE ALL                |                      |      1 |  46695 |      0 |00:04:30.17 |   95321 |   4557 |       |       |          |
    |   6 |     PARTITION HASH ALL                |                      |     62 |  46695 |      0 |00:04:30.17 |   95321 |   4557 |       |       |          |
    |*  7 |      TABLE ACCESS BY LOCAL INDEX ROWID| INV                  |    496 |  46695 |      0 |00:04:30.16 |   95321 |   4557 |       |       |          |
    |*  8 |       INDEX RANGE SCAN                | INV_ID1              |    496 |  47220 |  48147 |00:00:16.70 |    2202 |    309 |       |       |          |
    ------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    
    11g:
    --------------------------------------------------------------------------------------------------------------------------------------------------
    | Id  | Operation                   | Name                 | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
    --------------------------------------------------------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT            |                      |      1 |        |    396 |00:30:34.02 |   86M|      8265K|       |       |          |
    |   1 |  TABLE ACCESS BY INDEX ROWID| pi                   |      6 |      1 |      6 |00:00:00.01 |   20 |         0 |       |       |          |
    |*  2 |   INDEX UNIQUE SCAN         | pi_PKI               |      6 |      1 |      6 |00:00:00.01 |   14 |         0 |       |       |          |
    |   3 |  SORT ORDER BY              |                      |      1 |    500 |    396 |00:30:34.02 |   86M|      8265K| 86016 | 86016 |75776  (0)|
    |*  4 |   COUNT STOPKEY             |                      |      1 |        |    396 |00:30:34.02 |   86M|      8265K|       |       |          |
    |   5 |    PARTITION RANGE ALL      |                      |      1 |    500 |    396 |00:30:34.02 |   86M|      8265K|       |       |          |
    |   6 |     PARTITION HASH ALL      |                      |     62 |    500 |    396 |00:30:34.02 |   86M|      8265K|       |       |          |
    |*  7 |      TABLE ACCESS FULL      | INV                  |    496 |    500 |    396 |00:30:34.01 |   86M|      8265K|       |       |          |
    --------------------------------------------------------------------------------------------------------------------------------------------------

    ORA-01502: index 'String' or a partition of this index is unusable

    Cause: You tried to access an index or an index partition that has been marked unusable by a direct load or by a DDL operation

    Action: REMOVE the index specified, REBUILD the specified index or REBUILD the unusable index partition

  • ORA-01502 error in the case of a unique index unusable and dml in bulk

    Hi all.

    The BP is 11.2.0.3 on a linux machine.

    I did a unique index unusable and issued a dml on the table.
    Howerver, oracle gave me the error ORA-01502.

    In order to avoid the ORA-01502 error, should I drop the unique index and bulk make dml and rebuild the index?

    Or is there another solution without recreating the unique index?
    create table hoho.abcde as
    select level col1 from dual connect by level <=1000 
    
    10:09:55 HOHO@PD1MGD>create unique index hoho.abcde_dx1 on hoho.abcde (col1);
    
    Index created.
    
    10:10:23 HOHO@PD1MGD>alter index hoho.abcde_dx1 unusable;
    
    Index altered.
    
    Elapsed: 00:00:00.03
    10:11:27 HOHO@PD1MGD>delete from hoho.abcde where rownum < 11;
    delete from hoho.abcde where rownum < 11
    *
    ERROR at line 1:
    ORA-01502: index 'HOHO.ABCDE_DX1' or partition of such index is in unusable state
    Thanks in advance.
    Best regards.
    Do I have to accept the unique index maintenance workload(undo generation/redo for undo generation)
    when doing bulk dml?
    

    I think so.

    The amount of data you load compared to existing data in the table?

    If say for example, you add 20%, and then to compare the retention of 20% adds data during the major part collect to create all of the index after insertion so
    you choose the drop/recreate the unique index

    Best regards

    Mohamed Houri
    www.hourim.WordPress.com

  • index partition unusable

    Hello

    If I score partitioned unusable index.
    as to change the < index_name > index unusable.
    all parttions of the index would become unusable?

    Thank you
    Pramod

    Hi, Yes, specify
    UNUSABLE to mark the index or indexes and partitions or index subpartition (s) UNUSABLE.

  • When I change a column is a primary key the associated non-unique index to become unique?

    So basically I already tried this and it shows me that the associated index is not unique.

    create table employees2 in select * from employees;

    create index emp_idx on employees2 (employee_id);

    ALTER employees2 table add primary key (employe_id) using index emp_idx;

    Select * from user_indexes where index-name = "EMP_IDX";

    I was wondering if I right assuming that when you change a column to a primary key or unique while using a given index that does not have the respective index become unique.

    The textbooks I use are sometimes a little hard to understand because of the wording, also, I want to just ask someone with a little more experience than me.

    Thank you.

    your test did give the correct answer: the index is not unique if it serves to bear a unique or primary key constraint. Indeed, it is one of the benefits of the use of no unique indexes in support of UK/PK constraints (since it allows to set the unusable index before to make bulk loads; and, of course, they have also some disadvantages - for example, they need an additional logical reading to reach a line). Richard Foote explains the details in https://richardfoote.wordpress.com/2008/06/04/primary-keys-and-non-unique-indexes-whats-really-happening/ (and other items).

  • Causes of invalid index

    Oracle 11.2.0.1
    Windows

    Can someone please give me link or a complete list reasons that can cause an invalidate index.

    I just want to know all the resons whereby a valid index becomes invalid.

    Thank you.

    1. change the index unusable.
    2. in the standard definition, an index becomes unusable when the database recognizes that the ROWID in the index point is no longer in the lines in the table. This can occur when the table is moved, compressed, etc while the index is inaccessible.
    3.SQL * loader fails to update the index because the index is running out of space.
    4. the instance fails during the construction of the index.
    5.A single key has duplicate values.
    6. an index is not in the same order than indicated by a sorted index clause.
    7 truncate a table still makes an unusable index can be used.
    8. the data are not in the order specified by the SORT of INDEX clause.
    9. There was a key duplicated in a unique index.
    10. nested data is used, and the load fails or is completed by an interruption of the keyboard after a data backup point has occurred.
    11. any operation level table partition like divide, move, import, share, merge, truncate, drop except add parition. all indexes non-partitioned and partitioned overall becames unusable; Although locally partitioned index only affects key partitions.
    12 perform a redefinition in line a table because these moves the valuse ROWID. And that causes the Index to become unusable.

    Source: [url http://docs.oracle.com/cd/B19306_01/server.102/b14215/ldr_modes.htm#sthref1486] Documentation, this forum and the Page n ° 127 Expert indexing in Oracle Database 11g by Darl Kuhn, Sam R. Alapati, Bill Padfield.

    This isn't an exhaustive list, but I guess these are the main causes of the unusable indexes.

    Concerning
    Girish Sharma

  • INDEX RANGE SCAN against INDEX SKIP SCAN

    Dear,

    Let me introduce you to the model, and then I'll ask my question
    SQL> select * from v$version;
    
    BANNER
    ----------------------------------------------------------------
    Oracle Database 10g Enterprise Edition Release 10.2.0.5.0 - 64bi
    PL/SQL Release 10.2.0.5.0 - Production
    CORE    10.2.0.5.0      Production
    TNS for Solaris: Version 10.2.0.5.0 - Production
    NLSRTL Version 10.2.0.5.0 - Production
    
    SQL> create table t1
      2     as select rownum                  id1,
      3      mod(rownum,1000)                  id2,
      4      lpad(rownum,10,'0')              small_vc,
      5      rpad('x',1000)                   padding
      6  from dual
      7  connect by level <= 10000;
    
    Table created.
    
    SQL> create index t1_ind_id1 on t1(id1);
    
    Index created.
    
    SQL> create index t1_ind_id2 on t1(id2, id1);
    
    Index created.
    
    SQL> exec dbms_stats.gather_table_stats(user, 't1', cascade => true);
    
    PL/SQL procedure successfully completed.
    
    SQL> select index_name, num_rows, clustering_factor
      2  from user_indexes
      3  where index_name in ('T1_IND_ID1','T1_IND_ID2');
    
    INDEX_NAME                       NUM_ROWS CLUSTERING_FACTOR
    ------------------------------ ---------- -----------------
    T1_IND_ID1                          10000              1429
    T1_IND_ID2                          10000             10000
    
    
    SQL> select *
      2  from t1
      3  where id1=6;
    
     Execution Plan
    ----------------------------------------------------------
    Plan hash value: 2367654148
    
    ------------------------------------------------------------------------------------------
    | Id  | Operation                   | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
    ------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT            |            |     1 |  1019 |     2   (0)| 00:00:01 |
    |   1 |  TABLE ACCESS BY INDEX ROWID| T1         |     1 |  1019 |     2   (0)| 00:00:01 |
    |*  2 |   INDEX RANGE SCAN          | T1_IND_ID1 |     1 |       |     1   (0)| 00:00:01 |
    ------------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       2 - access("ID1"=6)
    So far so good.

    What I want is to know how I can reproduce an example of real life where an index skip scan has been chosen by the CBO despite the presence of the index 'adequate '.

    Here, below, I tried several examples
    SQL> alter index t1_ind_id1 unusable;
    
    Index altered.
    
    SQL> select *
      2  from t1
      3  where id1=6;
    
      Execution Plan
    ----------------------------------------------------------
    Plan hash value: 2497247906
    
    ------------------------------------------------------------------------------------------
    | Id  | Operation                   | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
    ------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT            |            |     1 |  1019 |  1004   (1)| 00:00:03 |
    |   1 |  TABLE ACCESS BY INDEX ROWID| T1         |     1 |  1019 |  1004   (1)| 00:00:03 |
    |*  2 |   INDEX SKIP SCAN           | T1_IND_ID2 |     1 |       |  1003   (1)| 00:00:03 |
    ------------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       2 - access("ID1"=6)
           filter("ID1"=6)
    It's predictable. Let replace them the usable index and change its grouping factor
    SQL> alter index t1_ind_id1 rebuild;
    
    Index altered.
    
    SQL> select *
      2  from t1
      3  where id1=6;
    
         
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 2367654148
    
    ------------------------------------------------------------------------------------------
    | Id  | Operation                   | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
    ------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT            |            |     1 |  1019 |     2   (0)| 00:00:01 |
    |   1 |  TABLE ACCESS BY INDEX ROWID| T1         |     1 |  1019 |     2   (0)| 00:00:01 |
    |*  2 |   INDEX RANGE SCAN          | T1_IND_ID1 |     1 |       |     1   (0)| 00:00:01 |
    ------------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       2 - access("ID1"=6)
    
    SQL> exec dbms_stats.set_index_stats(user, 'T1_IND_ID1',clstfct => 20000);
    
    PL/SQL procedure successfully completed.
    
    SQL> select index_name, num_rows, clustering_factor
      2  from user_indexes
      3  where index_name in ('T1_IND_ID1','T1_IND_ID2');
    
    INDEX_NAME                       NUM_ROWS CLUSTERING_FACTOR
    ------------------------------ ---------- -----------------
    T1_IND_ID1                          10000             20000
    T1_IND_ID2                          10000             10000
    
    
    SQL> select *
      2  from t1
      3  where id1=6;
    
        
    Execution Plan
    ------------------------------------------------------------------------------------------
    Plan hash value: 2367654148
    ------------------------------------------------------------------------------------------
    | Id  | Operation                   | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
    ------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT            |            |     1 |  1019 |     3   (0)| 00:00:01 |
    |   1 |  TABLE ACCESS BY INDEX ROWID| T1         |     1 |  1019 |     3   (0)| 00:00:01 |
    |*  2 |   INDEX RANGE SCAN          | T1_IND_ID1 |     1 |       |     1   (0)| 00:00:01 |
    ------------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       2 - access("ID1"=6)
    Still without success to produce an INDEX SKIP SCAN on T1_IND_ID2 in the presence of the T1_IND_ID1 index

    Any suggestions?

    Thank you

    Mohamed Houri
    www.hourim.WordPress.com

    What I want is to know how I can reproduce an example of real life where an index skip scan has been chosen by the CBO despite the presence of the 'adequate' index

    If, on behalf of the investigation, trying to 'force' the index skip scan, you must do two things:

    1. change the factor of grouping of TI_IND_ID1 to make it more expensive.

    While Hemant and Nikolay make good points on the fact that the grouping factor SHOULD BE irrelevant for a search of a single line, you are using a non-unique index is still part of the calculation of costs for a range scan.

    It had been a unique index so the factor of grouping of piracy would have been ineffective.

    But because only the cost calculation involves selectivity * factor clustering, you must change it by an order of magnitude (relevant to num_distinct obviously) to make significant change.

    For example:

    SQL> exec dbms_stats.set_index_stats(user, 'T1_IND_ID1',clstfct => 20000000);
    
    PL/SQL procedure successfully completed.
    
    SQL> explain plan for
      2  select /*+ index(t1 t1_ind_id1) */ *
      3  from t1
      4  where id1=6;
    
    Explained.
    
    SQL> select * from table(dbms_xplan.display);
    
    PLAN_TABLE_OUTPUT
    ---------------------------------------------------------------------------------------------------------
    Plan hash value: 3180815200
    
    ------------------------------------------------------------------------------------------
    | Id  | Operation                   | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
    ------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT            |            |     1 |  1019 |  2002   (1)| 00:00:25 |
    |   1 |  TABLE ACCESS BY INDEX ROWID| T1         |     1 |  1019 |  2002   (1)| 00:00:25 |
    |*  2 |   INDEX RANGE SCAN          | T1_IND_ID1 |     1 |       |     1   (0)| 00:00:01 |
    ------------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       2 - access("ID1"=6)
    
    14 rows selected.
    
    SQL>
    

    This pushes the cost of analysis of the range up above the table scan complete:

    SQL> explain plan for
      2  select *
      3  from t1
      4  where id1=6;
    
    Explained.
    
    SQL>  select * from table(dbms_xplan.display);
    
    PLAN_TABLE_OUTPUT
    -----------------------------------------------------------------------------------------------
    Plan hash value: 3617692013
    
    --------------------------------------------------------------------------
    | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    --------------------------------------------------------------------------
    |   0 | SELECT STATEMENT  |      |     1 |  1019 |   322   (1)| 00:00:04 |
    |*  1 |  TABLE ACCESS FULL| T1   |     1 |  1019 |   322   (1)| 00:00:04 |
    --------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - filter("ID1"=6)
    
    13 rows selected.
    
    SQL>
    

    So, now to the next step.

    2. we need to artificially reduce the cost of the analysis of Skip - and the best way to do that is by changing the separate issue of the main column in the index (currently 1000):

    SQL> begin
      2     DBMS_STATS.SET_COLUMN_STATS
      3     (ownname       => USER,
      4      tabname       => 'T1',
      5      colname       => 'ID2',
      6      partname      => NULL,
      7      stattab       => NULL,
      8      statid        => NULL,
      9      distcnt       => 1,
     10      density       => 1,
     11      nullcnt       => 0,
     12      srec          => NULL,
     13      avgclen       => 4,
     14      flags         => NULL,
     15      statown       => NULL,
     16      no_invalidate => FALSE,
     17      force         => TRUE);
     18  end;
     19  /
    
    PL/SQL procedure successfully completed.
    
    SQL> 
    

    As a Skip Scan is now taken over by default:

    SQL> explain plan for
      2  select *
      3  from t1
      4  where id1=6;
    
    Explained.
    
    SQL> select * from table(dbms_xplan.display);
    
    PLAN_TABLE_OUTPUT
    ---------------------------------------------------------------------------------------------------
    Plan hash value: 3198394326
    
    ------------------------------------------------------------------------------------------
    | Id  | Operation                   | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
    ------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT            |            |     1 |  1019 |     3   (0)| 00:00:01 |
    |   1 |  TABLE ACCESS BY INDEX ROWID| T1         |     1 |  1019 |     3   (0)| 00:00:01 |
    |*  2 |   INDEX SKIP SCAN           | T1_IND_ID2 |     1 |       |     2   (0)| 00:00:01 |
    ------------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       2 - access("ID1"=6)
           filter("ID1"=6)
    
    15 rows selected.
    
    SQL>
    

    Hope this helps

    Published by: Dom Brooks on October 24, 2012 12:49
    Reformulated

Maybe you are looking for