Question :
According to the documentation,
“Use the constant DBMS_STATS.AUTO_CASCADE to have Oracle determine whether index statistics are to be collected or not.”
But it seems like AUTO_CASCADE will always gather index statistics, even when it obviously does not need to.
This test case demonstrates the problem:
SQL> --Create table
SQL> create table statistics_test(a number, b number, c number, d number, e number);
Table created.
SQL> --Add 10 million rows (about 320 MB)
SQL> begin
2 for i in 1 .. 100 loop
3 insert into statistics_test
4 select level, level, level, level, level from dual
5 connect by level <= 100000;
6 end loop;
7 commit;
8 end;
9 /
PL/SQL procedure successfully completed.
SQL> --Create large index (AFTER the data load)
SQL> create index statistics_test_index on statistics_test(a,b,c,d,e);
Index created.
SQL> --Statistics are automatically gathered on index creation or rebuild.
SQL> select to_char(last_analyzed, 'HH24:MI:SS') last_analyzed
2 from user_indexes
3 where index_name = 'STATISTICS_TEST_INDEX';
LAST_ANA
--------
16:11:43
SQL> --Gather stats, use AUTO_CASCADE.
SQL> exec dbms_stats.gather_table_stats(user, 'STATISTICS_TEST', cascade => DBMS_STATS.AUTO_CASCADE);
PL/SQL procedure successfully completed.
SQL> --FAIL: Time changed - index was re-analyzed even though no data changed.
SQL> select to_char(last_analyzed, 'HH24:MI:SS') last_analyzed
2 from user_indexes
3 where index_name = 'STATISTICS_TEST_INDEX';
LAST_ANA
--------
16:12:12
SQL> --Let's assume that LAST_ANALYZED is lying.
SQL> --What I'm really worried about is the extra time spent analyzing indexes.
SQL> --Compare performance of AUTO_CASCADE, TRUE, and FALSE.
SQL> --FAIL: AUTO_CASCADE is as slow as TRUE. It should be as fast as FALSE.
SQL> set timing on
SQL> exec dbms_stats.gather_table_stats(user, 'STATISTICS_TEST', cascade => DBMS_STATS.AUTO_CASCADE);
PL/SQL procedure successfully completed.
Elapsed: 00:00:20.80
SQL> exec dbms_stats.gather_table_stats(user, 'STATISTICS_TEST', cascade => true);
PL/SQL procedure successfully completed.
Elapsed: 00:00:19.58
SQL> exec dbms_stats.gather_table_stats(user, 'STATISTICS_TEST', cascade => false);
PL/SQL procedure successfully completed.
Elapsed: 00:00:08.27
I do not think it matters, but my system is using the default for ESTIMATE_PERCENT, METHOD_OPT, DEGREE, GRANULARITY, CASCADE, and NO_INVALIDATE. I can reproduce this issue on 10.2.0.4, 11.2.0.1, 11.2.0.3, and 12.2.0.1.
This looks like a bug, but I can’t find anything on My Oracle Support. And it’s strange that a default setting, with significant performance impact, would be completely broken for so long.
Am I missing something here?
Answer :
Are you sure the index was analyzed – or was it just that DBMS_STATS
updated the LAST_ANALYZED
timestamp? The best way to find out it to trace the process performing the analysis.