Does DBMS_STATS.AUTO_CASCADE ever work?

Posted on

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.

Leave a Reply

Your email address will not be published. Required fields are marked *