We have a query that was getting poor performance. The root of the problem could be reproduced using a simple query accessing only one index to retrieve one column (the indexed column) from eight rows. The table had no statistics on it, yet the index did. Gathering new statistics on the index did not change the plan, but gathering statistics on the table did. My understanding was that a query that could be satisfied using only the index would not have to access the table, therefore my mental model was that table statistics would not matter in this case, but experience seems to indicate otherwise. Both the explain plan and auto-trace plan show only index access, yet when the table statistics are not present there is significantly higher cost and cardinality. The autotrace shows higher CPU, DB Time and Consistent Gets. I have not tried to trace it yet, but I can reproduce it by creating/dropping statistics on the table as shown below. Can anyone explain this behavior? set serveroutput on DECLARE numr NUMBER; numb NUMBER; avgr NUMBER; nrow NUMBER; nblk NUMBER; numd NUMBER; avgl NUMBER; avgd NUMBER; cfac NUMBER; ilvl NUMBER; gues NUMBER; BEGIN --Gather Stats. dbms_stats.Gather_table_Stats(USER,'RESULTS'); --Gather Index Stats. dbms_stats.Gather_index_Stats(USER,'I1'); --Show Index Stats. dbms_stats.get_index_stats(USER, 'I1', NULL, NULL, NULL, nrow, nblk , numd, avgl, avgd, cfac, ilvl, NULL, gues); dbms_output.put_line('Number of rows: ' || TO_CHAR(nrow)); dbms_output.put_line('Number of blocks: ' || TO_CHAR(nblk)); dbms_output.put_line('Distinct keys: ' || TO_CHAR(numd)); dbms_output.put_line('Avg leaf blocks/key: ' || TO_CHAR(avgl)); dbms_output.put_line('Avg data blocks/key: ' || TO_CHAR(avgd)); dbms_output.put_line('Clustering factor: ' || TO_CHAR(cfac)); dbms_output.put_line('Index level: ' || TO_CHAR(ilvl)); dbms_output.put_line('IOT guess quality: ' || TO_CHAR(gues)); delete from plan_table; END; / EXPLAIN PLAN FOR SELECT rsample_id FROM results WHERE rsample_id = '0555103360'; SELECT cost, substr(lpad(' ', level-1) || operation || ' (' || options || ')',1,50 ) "Operation", object_name "Object" FROM plan_table START WITH ID = 0 CONNECT BY PRIOR id=parent_id; DECLARE nrow NUMBER; nblk NUMBER; numd NUMBER; avgl NUMBER; avgd NUMBER; cfac NUMBER; ilvl NUMBER; gues NUMBER; BEGIN --Delete Stats. dbms_stats.delete_table_stats(USER,'RESULTS'); --Gather Index Stats. dbms_stats.Gather_index_Stats('LRIFFEL','I1'); --Show Index Stats. dbms_stats.get_index_stats(USER, 'I1', NULL, NULL, NULL, nrow, nblk , numd, avgl, avgd, cfac, ilvl, NULL, gues); dbms_output.put_line('Number of rows: ' || TO_CHAR(nrow)); dbms_output.put_line('Number of blocks: ' || TO_CHAR(nblk)); dbms_output.put_line('Distinct keys: ' || TO_CHAR(numd)); dbms_output.put_line('Avg leaf blocks/key: ' || TO_CHAR(avgl)); dbms_output.put_line('Avg data blocks/key: ' || TO_CHAR(avgd)); dbms_output.put_line('Clustering factor: ' || TO_CHAR(cfac)); dbms_output.put_line('Index level: ' || TO_CHAR(ilvl)); dbms_output.put_line('IOT guess quality: ' || TO_CHAR(gues)); delete from plan_table; END; / EXPLAIN PLAN FOR SELECT rsample_id FROM results WHERE rsample_id = '0555103360'; SELECT cost, substr(lpad(' ', level-1) || operation || ' (' || options || ')',1,50 ) "Operation", object_name "Object" FROM plan_table START WITH ID = 0 CONNECT BY PRIOR id=parent_id; This had the following output (modified to fit): anonymous block completed Number of rows: 125226611 Number of blocks: 381090 Distinct keys: 5778886 Avg leaf blocks/key: 1 Avg data blocks/key: 3 Clustering factor: 19792294 Index level: 3 IOT guess quality: plan FOR succeeded. COST Operation Object ----- --------------------- ------ 4 SELECT STATEMENT() 4 INDEX (RANGE SCAN) I1 anonymous block completed Number of rows: 119034073 Number of blocks: 362402 Distinct keys: 5353024 Avg leaf blocks/key: 1 Avg data blocks/key: 3 Clustering factor: 18852918 Index level: 3 IOT guess quality: plan FOR succeeded. COST Operation Object ----- --------------------- ------ 9 SELECT STATEMENT() 9 INDEX (RANGE SCAN) I1 After creating this I noticed that the index statistics were different for each run even though nothing should be changing in the table and index statistics are re-gathered on each run. My theory now is that something on the index statistics is retained when gathering table statistics with the cascade option even when index statistics are re-gathered. Granularity is set to AUTO and Cascade is set to AUTO_CASCADE.