SlideShare a Scribd company logo
1 of 16
Download to read offline
1, what oracle document tells us?
For partitioned tables, when we collect statistics, even when only one partition changed, such as
add a new partition or load some data to a partition,
we have to scan all partitions to compute global statistics, this is much resource intensive
operation.

In 11G, oracle introduced “incremental” statistics gather option for partitioned table. When a
partitioned table is set to “incremental” attribute, it will store
a synopsis on sysaux tablespace for global level statistics(it will only consume very little
space), then, it will only scan one partition but will update
the global statistics, which will save many resource.

2, my test:
2.0: My Test Environments:
Oracle version is: 11.1.0.6,
OS: Solaris


2.1 create test table:
Let us create 2 tables test_inc(enable incremental statistics) and test_inc_bak(disable
incremental statistics) with same structure:
SQL> create table test_inc
                  test_inc(a number, b          date, c varchar2(30), d varchar2(100), e
varchar2(100), partition_key number)
  2 partition by range(partition_key)
  3 (
  4     partition p00 values less than          (1),
  5     partition p01 values less than          (2),
  6     partition p02 values less than          (3),
  7     partition p03 values less than          (4),
  8     partition p04 values less than          (5),
  9     partition p05 values less than          (6),
 10     partition p06 values less than          (7),
 11     partition p07 values less than          (8),
 12     partition p08 values less than          (9),
 13     partition p09 values less than          (10),
 14     partition p10 values less than          (11),
 15     partition p11 values less than          (12),
 16     partition p12 values less than          (13),
 17     partition p13 values less than          (14),
 18     partition p14 values less than          (15),
 19     partition p15 values less than          (16),
 20     partition p16 values less than          (17),
 21     partition p17 values less than          (18),
 22     partition p18 values less than          (19),
 23     partition p19 values less than          (20),
 24     partition p20 values less than          (21),
 25     partition p21 values less than          (22),
 26     partition p22 values less than          (23),
 27     partition p23 values less than          (24),
 28     partition p24 values less than          (25),
 29     partition p25 values less than          (26),
 30     partition p26 values less than          (27),
 31     partition p27 values less than          (28),
 32     partition p28 values less than          (29),
33      partition p29 values less than (30),
 34      partition p30 values less than (31),
 35      partition pmax values less than(maxvalue)
 36   ) ;

SQL> create table test_inc_bak
                  test_inc_bak(a number, b date, c varchar2(30), d
varchar2(100), e varchar2(100), partition_key number)
  2 partition by range(partition_key)
  3 (
  4     partition p00 values less than (1),
  5     partition p01 values less than (2),
  6     partition p02 values less than (3),
  7     partition p03 values less than (4),
  8     partition p04 values less than (5),
  9     partition p05 values less than (6),
 10     partition p06 values less than (7),
 11     partition p07 values less than (8),
 12     partition p08 values less than (9),
 13     partition p09 values less than (10),
 14     partition p10 values less than (11),
 15     partition p11 values less than (12),
 16     partition p12 values less than (13),
 17     partition p13 values less than (14),
 18     partition p14 values less than (15),
 19     partition p15 values less than (16),
 20     partition p16 values less than (17),
 21     partition p17 values less than (18),
 22     partition p18 values less than (19),
 23     partition p19 values less than (20),
 24     partition p20 values less than (21),
 25     partition p21 values less than (22),
 26     partition p22 values less than (23),
 27     partition p23 values less than (24),
 28     partition p24 values less than (25),
 29     partition p25 values less than (26),
 30     partition p26 values less than (27),
 31     partition p27 values less than (28),
 32     partition p28 values less than (29),
 33     partition p29 values less than (30),
 34     partition p30 values less than (31),
 35     partition pmax values less than(maxvalue)
 36 );

2.2 set incremental attribute for one table:
Let enable “incremental” statistics gathering for test_inc:
SQL> select DBMS_STATS.get_PREFS('incremental', 'wwf', 'test_inc') from
dual;

DBMS_STATS.GET_PREFS('INCREMENTAL','WWF','TEST_INC')
FALSE

SQL> exec
DBMS_STATS.SET_TABLE_PREFS(user,'test_inc','INCREMENTAL','TRUE')

PL/SQL procedure successfully completed.

SQL> select DBMS_STATS.get_PREFS('incremental', 'wwf', 'test_inc') from
dual;

DBMS_STATS.GET_PREFS('INCREMENTAL','WWF','TEST_INC')
TRUE

For test_inc_bak, keep it disabled for “incremental” statistics gathering:
SQL> select DBMS_STATS.get_PREFS('incremental', 'wwf', 'test_inc_bak') from dual;

DBMS_STATS.GET_PREFS('INCREMENTAL','WWF','TEST_INC_BAK')
---------------------------------------------------------------------------------------------------------------------------------
FALSE

2.3 The whole test process:
                                                                  populate
Then, using the following sql to populate data for each partition(populate 300k records for each
partition and change the value of partition key correspondingly
                                                    correspondingly):
insert into test_inc select rownum, sysdate+mod(rownum, 30),
'wangweifengwangweifeng'||rownum,
rpad('x', 50, 'x')||rownum, rpad('y', 50, 'z')||rownum, 0 from dual connect by
rownum <= 300000
          300000;

insert into test_inc_bak select rownum, sysdate+mod(rownum, 30),
'wangweifengwangweifeng'||rownum,
rpad('x', 50, 'x')||rownum, rpad('y', 50, 'z')||rownum, 0 from dual connect by
rownum <= 300000
          300000;


My test indicates that: the “incremental” attribute will make the statistics gathering process much
faster!

exec dbms_stats.gather_table_stats(user, 'test_inc')
exec dbms_stats.gather_table_stats(user, 'test_inc_bak')


2.4 test result and compare
The following table is the time spent for incremental/non-incremental tables statistics-gathering
process:

partition                   Time elapsed for incremental table                            Time elapsed for non-incremental table
number                              test_inc(seconds)
                                    test_inc(seconds
                                             seconds)                                             test_inc_bak (seconds)
                                                                                                                seconds)
                     1                                    4.37                                                                4.36
                     2                                    4.47                                                                8.66
                     3                                    5.09                                                                13.2
                     4                                    5.38                                                               19.48
                     5                                    5.47                                                               24.06
                     6                                    5.76                                                               29.39
                     7                                    6.13                                                               34.03
                     8                                    6.62                                                               38.97
                     9                                    7.28                                                               46.24
                    10                                    7.32                                                               50.75
                    11                                    7.53                                                               56.83
                    12                                    7.86                                                               62.25
                    13                                    8.62                                                               67.06
                    14                                    8.89                                                               72.73
                    15                                    9.48                                                               78.93
                    16                                   10.01                                                               83.66
                    17                                   10.77                                                               87.44
18                                     11.22                                            93.74
               19                                     10.72                                           100.85
               20                                     11.48                                           105.54
               21                                     11.01                                           112.08
               22                                     11.06                                           116.53
               23                                     10.68                                           123.57
               24                                     12.58                                           126.58
               25                                      8.01                                           135.41
               26                                     12.38                                           137.95
               27                                     13.09                                           144.33
               28                                     14.67                                           149.75
               29                                     13.55                                           153.94
               30                                     14.27                                           160.50
               31                                     14.15                                           165.50

Use the above data, let’s plot picture:
                        let’
We can see, for non-incremental partitioned table, the time elapsed for non-incremental (the
yellow line) is linear with the partition number.
While for the incremental partitioned table, the time elapsed (the red line) is nearly a flat line:




The red line represent time elapsed for incremental partitioned table
The yellow line time elapsed for non-incremental partitioned table
2.5: let’s see from another perspective: what last_analyzed column can tell
     let’
us?
SQL> exec dbms_stats.gather_table_stats(user, 'test_inc'
                                              'test_inc')

PL/SQL procedure successfully completed.

Elapsed: 00:00:04.37

SQL> select partition_name, blocks, num_rows, last_analyzed from
user_tab_partitions where table_name = 'TEST_INC' and num_rows > 0;

PARTITION_NAME                     BLOCKS   NUM_ROWS LAST_ANALYZED
------------------------------ ---------- ---------- -------------------
P00                                  6796     300000 2009-09-09 00:49:51

SQL> select table_name, blocks, num_rows, last_analyzed from
user_tables where table_name = 'TEST_INC';

TABLE_NAME                         BLOCKS   NUM_ROWS LAST_ANALYZED
------------------------------ ---------- ---------- -------------------
TEST_INC                            6796      300000 2009-09-09 00:49:51

Insert 300k records for empty partition p2:
SQL> exec dbms_stats.gather_table_stats(user, 'test_inc')

PL/SQL procedure successfully completed.

Elapsed: 00:00:04.47
SQL> select partition_name, blocks, num_rows, last_analyzed from
user_tab_partitions where table_name = 'TEST_INC' and num_rows > 0;

PARTITION_NAME                     BLOCKS   NUM_ROWS LAST_ANALYZED
------------------------------ ---------- ---------- -------------------
P00                                  6796     300000 2009-09-09 00:49:51
P01                                  6796     300000 2009-09-09 00:52:27

SQL> select table_name, blocks, num_rows, last_analyzed from user_tables where
table_name = 'TEST_INC';

TABLE_NAME                         BLOCKS   NUM_ROWS LAST_ANALYZED
------------------------------ ---------- ---------- -------------------
TEST_INC                            13592     600000 2009-09-09 00:52:29


Insert 300k records for empty partition p3:
SQL> exec dbms_stats.gather_table_stats(user, 'test_inc')

PL/SQL procedure successfully completed.

Elapsed: 00:00:05.09
SQL> select partition_name, blocks, num_rows, last_analyzed from
user_tab_partitions where table_name = 'TEST_INC' and num_rows > 0;

PARTITION_NAME                     BLOCKS   NUM_ROWS LAST_ANALYZED
------------------------------ ---------- ---------- -------------------
P00                                  6796     300000 2009-09-09 00:49:51
P01                                  6796     300000 2009-09-09 00:52:27
P02                                  6796     300000 2009-09-09 00:55:39
SQL> select table_name, blocks, num_rows, last_analyzed from user_tables where
table_name = 'TEST_INC';

TABLE_NAME                         BLOCKS   NUM_ROWS LAST_ANALYZED
------------------------------ ---------- ---------- -------------------
TEST_INC                            20388     900000 2009-09-09 00:55:40

Insert 300k records for empty partition p4:
SQL> exec dbms_stats.gather_table_stats(user, 'test_inc')

PL/SQL procedure successfully completed.

Elapsed: 00:00:05.38

SQL> select partition_name, blocks, num_rows, last_analyzed from
user_tab_partitions where table_name = 'TEST_INC'
  2 and num_rows > 0;

PARTITION_NAME                     BLOCKS   NUM_ROWS LAST_ANALYZED
------------------------------ ---------- ---------- -------------------
P00                                  6796     300000 2009-09-09 00:49:51
P01                                  6796     300000 2009-09-09 00:52:27
P02                                  6796     300000 2009-09-09 00:55:39
P03                                  6796     300000 2009-09-09 01:00:23

SQL> select table_name, blocks, num_rows, last_analyzed from
user_tables where table_name = 'TEST_INC';

TABLE_NAME                         BLOCKS   NUM_ROWS LAST_ANALYZED
------------------------------ ---------- ---------- -------------------
TEST_INC                            27184    1200000 2009-09-09 01:00:24

We can see that: the last_analyzed column won’t change after each analyze.
                                           won’
This can tell us that: the unchanged analyzed partition is skipped when enable incremental
statistics gathering.

But, let’s see the last_analyzed column for non-incremental partitions table:
     let’
The last_analyze column changes when every analyze: this is the last time I analyzed the
non-incremental table test_inc_bak(I started my test from 09/09/2009):
SQL> select partition_name, num_rows, blocks, last_analyzed from
user_tab_partitions where table_name = 'TEST_INC_BAK'
                                                  'TEST_INC_BAK';

PARTITION_NAME                   NUM_ROWS     BLOCKS LAST_ANALYZED
------------------------------ ---------- ---------- -------------------
P00                                300000       6796 2009-09-11 01:07:43
P01                                300000       6796 2009-09-11 01:07:46
P02                                300000       6796 2009-09-11 01:07:49
P03                                300000       6796 2009-09-11 01:07:52
P04                                300000       6796 2009-09-11 01:07:54
P05                                300000       6796 2009-09-11 01:07:57
P06                                300000       6796 2009-09-11 01:08:00
P07                                300000       6796 2009-09-11 01:08:03
P08                                300000       6796 2009-09-11 01:08:06
P09                                300000       6796 2009-09-11 01:08:09
P10                                300000       6796 2009-09-11 01:08:13
P11                                300000       6796 2009-09-11 01:08:16
P12                                300000       6796 2009-09-11 01:08:19
P13                                300000       6796 2009-09-11 01:08:22
P14                                300000       6796 2009-09-11 01:08:24
P15                                300000       6796 2009-09-11 01:08:27
P16                                       300000             6796   2009-09-11   01:08:30
P17                                       300000             6796   2009-09-11   01:08:33
P18                                       300000             6796   2009-09-11   01:08:36
P19                                       300000             6796   2009-09-11   01:08:39
P20                                       300000             6796   2009-09-11   01:08:42
P21                                       300000             6796   2009-09-11   01:08:45
P22                                       300000             6796   2009-09-11   01:08:48
P23                                       300000             6796   2009-09-11   01:08:51
P24                                       300000             6796   2009-09-11   01:08:54
P25                                       300000             6796   2009-09-11   01:08:57
P26                                       300000             6796   2009-09-11   01:09:00
P27                                       300000             6796   2009-09-11   01:09:03
P28                                       300000             6796   2009-09-11   01:09:06
P29                                       300000             6796   2009-09-11   01:09:09
P30                                       300000             6796   2009-09-11   01:09:11
PMAX                                           0                0   2009-09-11   01:09:11

While the following is what analyze looks like when I finish the analyze on incremental
table test_inc_bak:
SQL> select partition_name, num_rows, blocks, last_analyzed from
user_tab_partitions where table_name = 'TEST_INC''TEST_INC';

PARTITION_NAME                   NUM_ROWS     BLOCKS LAST_ANALYZED
------------------------------ ---------- ---------- -------------------
P00                                300000       6796 2009-09-09 00:49:51
P01                                300000       6796 2009-09-09 00:52:27
P02                                300000       6796 2009-09-09 00:55:39
P03                                300000       6796 2009-09-09 01:00:23
P04                                300000       6796 2009-09-09 01:04:59
P05                                300000       6796 2009-09-09 01:09:37
P06                                300000       6796 2009-09-09 01:14:06
P07                                300000       6796 2009-09-09 01:17:33
P08                                300000       6796 2009-09-09 01:22:14
P09                                300000       6796 2009-09-09 01:28:15
P10                                300000       6796 2009-09-09 01:33:29
P11                                300000       6796 2009-09-09 01:36:36
P12                                300000       6796 2009-09-09 01:42:39
P13                                300000       6796 2009-09-09 01:46:54
P14                                300000       6796 2009-09-09 01:55:36
P15                                300000       6796 2009-09-09 02:04:55
P16                                300000       6796 2009-09-09 02:20:34
P17                                300000       6796 2009-09-09 03:05:48
P18                                300000       6796 2009-09-09 03:38:40
P19                                300000       6796 2009-09-09 04:10:07
P20                                300000       6796 2009-09-09 04:14:57
P21                                300000       6796 2009-09-09 04:46:03
P22                                300000       6796 2009-09-09 04:57:09
P23                                300000       6796 2009-09-09 05:28:45
P24                                300000       6796 2009-09-11 22:03:14
P25                                300000       6796 2009-09-11 00:31:14
P26                                300000       6796 2009-09-11 00:37:14
P27                                300000       6796 2009-09-11 00:44:13
P28                                300000       6796 2009-09-11 00:52:49
P29                                300000       6796 2009-09-11 01:00:16
P30                                300000       6796 2009-09-11 01:06:34
PMAX                                    0          0 2009-09-11 01:06:34



2.6 The drawback or bugs of incremental statistics:

2.6.1: It is only sensitive for newly load data partition:
Per my test, it seems that, “incremental statistics” is only sensitive for a new partition which is
completely newly loaded data. It can be aware of the following situations:
    a. delete/insert some data to a partition that has already been analyzed
    b. truncate one/more partitions

Please see my test:
   The table currently has 1.8 million records, each partition contain 0.3 million records:

SQL> select partition_name, num_rows, blocks, last_analyzed from
user_tab_partitions where table_name = 'TEST_INC' and num_rows > 0;

PARTITION_NAME                   NUM_ROWS     BLOCKS LAST_ANALYZED
------------------------------ ---------- ---------- -------------------
P00                                300000       6796 2009-09-12 01:41:56
P01                                300000       6796 2009-09-12 01:45:07
P02                                300000       6796 2009-09-12 01:47:11
P03                                300000       6796 2009-09-12 01:50:11
P04                                300000       6796 2009-09-12 01:51:41
P05                                300000       6796 2009-09-12 01:52:48

Delete 100k records for partition p05:
SQL> delete from test_inc partition(p05) where rownum <= 100000;

100000 rows deleted.

Truncate partition p04:
SQL> alter table test_inc truncate partition p04 ;

Table truncated.

Insert 100k records to partition p01:
SQL> insert into test_inc select rownum, sysdate+mod(rownum, 30),
'wangweifengwangweifeng'||rownum,
  2 rpad('x', 50, 'x')||rownum, rpad('y', 50, 'z')||rownum, 1 from dual
connect by rownum <= 300000;

300000 rows created.


But, let us analyze it:
SQL> exec dbms_stats.gather_table_stats(user, 'test_inc');

PL/SQL procedure successfully completed.

SQL> select table_name, num_rows, blocks, last_analyzed from
user_tables where table_name = 'TEST_INC';

TABLE_NAME                       NUM_ROWS     BLOCKS LAST_ANALYZED
------------------------------ ---------- ---------- -------------------
TEST_INC                          1800000      41361 2009-09-12 01:57:21

SQL> select partition_name, num_rows, blocks, last_analyzed from
user_tab_partitions where table_name = 'TEST_INC' and num_rows > 0;

PARTITION_NAME                   NUM_ROWS     BLOCKS LAST_ANALYZED
------------------------------ ---------- ---------- -------------------
P00                                300000       6796 2009-09-12 01:41:56
P01                                300000       6796 2009-09-12 01:45:07
P02                                300000       6796 2009-09-12 01:47:11
P03                                      300000         6796 2009-09-12 01:50:11
P04                                      300000         6796 2009-09-12 01:51:41
P05                                      300000         6796 2009-09-12 01:52:48

6 rows selected.

SQL> select count(*) from test_inc partition(p05);

  COUNT(*)
----------
    200000

SQL> select count(*) from test_inc partition(p06);

  COUNT(*)
----------
         0

SQL> select count(*) from test_inc partition(p01);

  COUNT(*)
----------
    600000

We can see, the statistics does not change at all!
Then, will it triggered by populating data into a newly loaded partition?
It won’t! Let me insert data to an empty partition p06:
   won’

SQL> insert into test_inc select rownum, sysdate+mod(rownum, 30),
'wangweifengwangweifeng'||rownum,
  2 rpad('x', 50, 'x')||rownum, rpad('y', 50, 'z')||rownum, 6 from
dual connect by rownum <= 300000;

300000 rows created.

SQL> exec dbms_stats.gather_table_stats(user, 'test_inc');

PL/SQL procedure successfully completed.

Elapsed: 00:00:06.61
SQL> select table_name, num_rows, blocks, last_analyzed from
user_tables where table_name = 'TEST_INC';

TABLE_NAME                       NUM_ROWS     BLOCKS LAST_ANALYZED
------------------------------ ---------- ---------- -------------------
TEST_INC                          2100000      48157 2009-09-12 02:01:36

SQL> select partition_name, num_rows, blocks, last_analyzed from
user_tab_partitions where table_name = 'TEST_INC' and num_rows > 0;

PARTITION_NAME                   NUM_ROWS     BLOCKS LAST_ANALYZED
------------------------------ ---------- ---------- -------------------
P00                                300000       6796 2009-09-12 01:41:56
P01                                300000       6796 2009-09-12 01:45:07
P02                                300000       6796 2009-09-12 01:47:11
P03                                300000       6796 2009-09-12 01:50:11
P04                                300000       6796 2009-09-12 01:51:41
P05                                300000       6796 2009-09-12 01:52:48
P06                                     300000          6796 2009-09-12 02:01:33

7 rows selected.


How about I truncate all tables?
Let me initialize the table and populate 2.1 million records for 7 partitions:
SQL> select table_name, num_rows, blocks, last_analyzed from
user_tables where table_name = 'TEST_INC';

TABLE_NAME                       NUM_ROWS     BLOCKS LAST_ANALYZED
------------------------------ ---------- ---------- -------------------
TEST_INC                          2100000      47572 2009-09-12 04:05:18

SQL> select partition_name, num_rows, blocks, last_analyzed from
user_tab_partitions where table_name = 'TEST_INC' and num_rows > 0;

PARTITION_NAME                   NUM_ROWS     BLOCKS LAST_ANALYZED
------------------------------ ---------- ---------- -------------------
P00                                300000       6796 2009-09-12 03:53:58
P01                                300000       6796 2009-09-12 03:54:42
P02                                300000       6796 2009-09-12 03:55:24
P03                                300000       6796 2009-09-12 04:01:54
P04                                300000       6796 2009-09-12 04:03:33
P05                                300000       6796 2009-09-12 04:04:26
P06                                300000       6796 2009-09-12 04:05:16

7 rows selected.

SQL> truncate table test_inc;

Table truncated.

Elapsed: 00:00:02.24
SQL> exec dbms_stats.gather_table_stats(user, 'test_inc');

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.61
SQL> select table_name, num_rows, blocks, last_analyzed from
user_tables where table_name = 'TEST_INC';

TABLE_NAME                       NUM_ROWS     BLOCKS LAST_ANALYZED
------------------------------ ---------- ---------- -------------------
TEST_INC                                0          0 2009-09-12 04:09:43

SQL> select partition_name, num_rows, blocks, last_analyzed from
user_tab_partitions where table_name = 'TEST_INC' and num_rows > 0;

PARTITION_NAME                   NUM_ROWS     BLOCKS LAST_ANALYZED
------------------------------ ---------- ---------- -------------------
P00                                300000       6796 2009-09-12 03:53:58
P01                                300000       6796 2009-09-12 03:54:42
P02                                300000       6796 2009-09-12 03:55:24
P03                                300000       6796 2009-09-12 04:01:54
P04                                300000       6796 2009-09-12 04:03:33
P05                                300000       6796 2009-09-12 04:04:26
P06                                300000       6796 2009-09-12 04:05:16

7 rows selected.
We can see: the statistics for table level is got updated, but, it is not got updated for
partition level!
I think, it should be a bug! Anyway, I will file TAR for Oracle for clarify.

How to fix it temporarily? Set it back to “no-incremental”, then analyze again:
                                           no-incremental”
SQL> exec
DBMS_STATS.SET_TABLE_PREFS(user,'test_inc','INCREMENTAL','FALSE'          'FALSE'
                                                                          'FALSE');

PL/SQL procedure successfully completed.

SQL> select DBMS_STATS.get_PREFS('incremental', 'wwf', 'test_inc') from
dual;

DBMS_STATS.GET_PREFS('INCREMENTAL','WWF','TEST_INC')
-----------------------------------------------------------------------
FALSE

SQL> exec dbms_stats.gather_table_stats(user, 'test_inc');

PL/SQL procedure successfully completed.

SQL> select partition_name, num_rows, blocks, last_analyzed from
user_tab_partitions where table_name = 'TEST_INC' and num_rows > 0;

no rows selected

SQL> select table_name, num_rows, blocks, last_analyzed from
user_tables where table_name = 'TEST_INC';

TABLE_NAME                       NUM_ROWS     BLOCKS LAST_ANALYZED
------------------------------ ---------- ---------- -------------------
TEST_INC                                0          0 2009-09-12 04:18:34

SQL> select partition_name, num_rows, blocks, last_analyzed from
user_tab_partitions where table_name = 'TEST_INC';

PARTITION_NAME                   NUM_ROWS     BLOCKS LAST_ANALYZED
------------------------------ ---------- ---------- -------------------
P00                                     0          0 2009-09-12 04:18:34
P01                                     0          0 2009-09-12 04:18:34
P02                                     0          0 2009-09-12 04:18:34
P03                                     0          0 2009-09-12 04:18:34
P04                                     0          0 2009-09-12 04:18:34
P05                                     0          0 2009-09-12 04:18:34
P06                                     0          0 2009-09-12 04:18:34
P07                                     0          0 2009-09-12 04:18:34

2.6.2 For subpartition table, it is totally wrong:

SQL>   CREATE TABLE composite_rng_list (
  2    cust_id     NUMBER(10),
  3    cust_name   VARCHAR2(25),
  4    cust_state VARCHAR2(2),
  5    time_id     DATE)
  6    PARTITION BY RANGE(time_id)
  7    SUBPARTITION BY LIST (cust_state)
  8    SUBPARTITION TEMPLATE(
  9    SUBPARTITION west VALUES ('OR', 'WA'),
10   SUBPARTITION east VALUES ('NY', 'CT'),
 11   SUBPARTITION cent VALUES ('OK', 'TX')) (
 12   PARTITION per1 VALUES LESS THAN (TO_DATE('01/01/2008','DD/MM/YYYY')),
 13   PARTITION per2 VALUES LESS THAN (TO_DATE('01/01/2010','DD/MM/YYYY')),
 14   PARTITION per3 VALUES LESS THAN (TO_DATE('01/01/2012','DD/MM/YYYY')),
 15   PARTITION future VALUES LESS THAN(MAXVALUE));

Table created.

SQL> exec dbms_stats.set_table_prefs('wwf', 'composite_rng_list',
'incremental', 'true')

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.01
SQL> select dbms_stats.get_prefs('incremental', 'wwf',
'composite_rng_list') from dual;

DBMS_STATS.GET_PREFS('INCREMENTAL','WWF','COMPOSITE_RNG_LIST')
---------------------------------------------------------------------
TRUE

SQL> insert into composite_rng_list select rownum, 'customer'||rownum, 'OR',
to_date('2007-01-01', 'yyyy-mm-dd') from dual connect by rownum <= 100000;

100000 rows created.

SQL> commit;

Commit complete.

SQL> select table_name, num_rows, blocks, last_analyzed from user_tables where
table_name = 'COMPOSITE_RNG_LIST';

TABLE_NAME                       NUM_ROWS     BLOCKS LAST_ANALYZED
------------------------------ ---------- ---------- -------------------
COMPOSITE_RNG_LIST                 100000        496 2009-09-14 18:17:58

Elapsed: 00:00:00.01
SQL> select partition_name, num_rows, blocks, last_analyzed from
user_tab_partitions where table_name = 'COMPOSITE_RNG_LIST' and rownum > 0;

PARTITION_NAME    NUM_ROWS     BLOCKS LAST_ANALYZED
---------------- ---------- ---------- -------------------
PER1               100000        496   2009-09-14 18:17:57

Elapsed: 00:00:00.00
SQL> select partition_name, SUBPARTITION_NAME, num_rows, blocks, last_analyzed
from user_tab_subpartitions where table_name = 'COMPOSITE_RNG_LIST' and rownum
> 0;

PARTITION_NAME    SUBPARTITION_NAME NUM_ROWS      BLOCKS LAST_ANALYZED
---------------- ---------------- ----------   ---------- -------------------
PER1              PER1_WEST          100000        496 2009-09-14 18:17:55

Then, insert 100000 more rows and analyze again, we can see that, the
statistics at partition level and table level were not changed at all:
SQL> insert into composite_rng_list select rownum, 'customer'||rownum, 'WA',
to_date('2007-01-01', 'yyyy-mm-dd') from dual connect by rownum <= 100000;
100000 rows created.

SQL> commit;

Commit complete.
SQL> exec dbms_stats.gather_table_stats(user, 'COMPOSITE_RNG_LIST',
granularity=>'ALL')

PL/SQL procedure successfully completed.

SQL> select table_name, num_rows, blocks, last_analyzed from user_tables where
table_name = 'COMPOSITE_RNG_LIST';

TABLE_NAME                       NUM_ROWS     BLOCKS LAST_ANALYZED
------------------------------ ---------- ---------- -------------------
COMPOSITE_RNG_LIST                 100000       1000 2009-09-14 18:24:12

SQL> select partition_name, num_rows, blocks, last_analyzed from
user_tab_partitions where table_name = 'COMPOSITE_RNG_LIST' and num_rows > 0;

PARTITION_NAME                   NUM_ROWS     BLOCKS LAST_ANALYZED
------------------------------ ---------- ---------- -------------------
PER1                               100000        496 2009-09-14 18:17:57

SQL> select partition_name, SUBPARTITION_NAME, num_rows, blocks, last_analyzed
from user_tab_subpartitions where table_name = 'COMPOSITE_RNG_LIST' and
num_rows > 0;

PARTITION_NAME SUBPARTITION_NAME   NUM_ROWS     BLOCKS   LAST_ANALYZED
--------------- --------------     ---------- ---------- -------------------
PER1                PER1_WEST       200000       1000     2009-09-14 18:24:11

Then, insert 100000 more rows and analyze again, we can see that, the
statistics at partition level and table level were not changed at all:
SQL> insert into composite_rng_list select rownum, 'customer'||rownum,
'NY', to_date('2007-01-01', 'yyyy-mm-dd') from dual connect by rownum <=
100000;

100000 rows created.

SQL> commit;

Commit complete.

SQL> exec dbms_stats.gather_table_stats(user, 'COMPOSITE_RNG_LIST',
granularity=>'ALL')

PL/SQL procedure successfully completed.

SQL> select table_name, num_rows, blocks, last_analyzed from user_tables where
table_name = 'COMPOSITE_RNG_LIST';

TABLE_NAME                       NUM_ROWS     BLOCKS LAST_ANALYZED
------------------------------ ---------- ---------- -------------------
COMPOSITE_RNG_LIST                 100000       1496 2009-09-14 18:26:33

SQL> select partition_name, num_rows, blocks, last_analyzed from
user_tab_partitions where table_name = 'COMPOSITE_RNG_LIST' and num_rows > 0;

PARTITION_NAME    NUM_ROWS     BLOCKS    LAST_ANALYZED
----------------- ---------- ---------- -------------------
PER1               100000        496     2009-09-14 18:17:57
SQL> select partition_name, SUBPARTITION_NAME, num_rows, blocks, last_analyzed
from user_tab_subpartitions where table_name = 'COMPOSITE_RNG_LIST' and
num_rows > 0;

PARTITION_NAME SUBPARTITION_NAME NUM_ROWS     BLOCKS           LAST_ANALYZED
------------ ----------------- ---------- ----------           -------------------
PER1             PER1_WEST         200000       1000           2009-09-14 18:26:32
PER1             PER1_EAST         100000        496           2009-09-14 18:26:32

Also, I do more test on subpartitione table. It can not display
accurate statistics on partition level and table level.

2.6.3 There is no incremental statistics for partitioned indexes on partitioned tables:

On the partitioned table in 2.1, we create a local partitioned index:
SQL> create index ind_test_inc on test_inc(a) local;

Index created.

Insert 300k rows, then analyze:
SQL> select partition_name, num_rows, DISTINCT_KEYS, clustering_factor,
last_analyzed from user_ind_partitions where index_name = 'IND_TEST_INC' and
num_rows > 0;

PARTITION_NAME        NUM_ROWS DISTINCT_KEYS CLUSTERING_FACTOR LAST_ANALYZED
---------------       --------- ------------- ----------------- ------------------
P00                    300000        300000              6763 2009-09-14 19:43:01

Insert 300k rows, then analyze:
SQL> select partition_name, num_rows, DISTINCT_KEYS, clustering_factor,
last_analyzed from user_ind_partitions where index_name = 'IND_TEST_INC' and
num_rows > 0;

PARTITION_NAME NUM_ROWS DISTINCT_KEYS  CLUSTERING LAST_ANALYZED
                                         FACTOR
------------- ---------- ------------- ----------------- --------------
P00           300000        300000        6763     2009-09-14 19:54:35
P01           300000        300000        6763     2009-09-14 19:54:35

Insert 300k rows, then, analyze:
SQL> select num_rows, DISTINCT_KEYS, clustering_factor, last_analyzed from
user_indexes where index_name = 'IND_TEST_INC';

  NUM_ROWS DISTINCT_KEYS CLUSTERING_FACTOR LAST_ANALYZED
---------- ------------- ----------------- -------------------
    900000        302976             20289 2009-09-14 20:00:50

SQL> select partition_name, num_rows, DISTINCT_KEYS, clustering_factor,
last_analyzed from user_ind_partitions where index_name = 'IND_TEST_INC' and
num_rows > 0;

PARTITION_NAME NUM_ROWS DISTINCT_KEYS CLUSTERING_FACTOR LAST_ANALYZED
--------------- ---------- ------------- ----------------- -------------------
P00              300000        300000              6763 2009-09-14 20:00:50
P01              300000        300000              6763 2009-09-14 20:00:50
P02              300000        300000              6763 2009-09-14 20:00:50

It seems that there is no way to set index “ind_test_inc” as incremental:
                                            ind_test_inc”
SQL> select dbms_stats.get_prefs('incremental', 'wwf', 'test_inc') from dual;

DBMS_STATS.GET_PREFS('INCREMENTAL','WWF','TEST_INC')
--------------------------------------------
TRUE

Elapsed: 00:00:00.01
SQL> select dbms_stats.get_prefs('incremental', 'wwf', 'ind_test_inc' from
                                                       'ind_test_inc')
dual;

DBMS_STATS.GET_PREFS('INCREMENTAL','WWF','IND_TEST_INC')
-----------------------------------------------
FALSE

Elapsed: 00:00:00.01
SQL> exec dbms_stats.set_table_prefs('wwf', 'ind_test_inc' 'incremental',
                                            'ind_test_inc',
'true')
BEGIN dbms_stats.set_table_prefs('wwf', 'ind_test_inc', 'incremental', 'true');
END;

*
ERROR at line 1:
ORA-20000: TABLE "WWF"."IND_TEST_INC" does not exist or insufficient privileges
ORA-06512: at "SYS.DBMS_STATS", line 2091
ORA-06512: at "SYS.DBMS_STATS", line 24110
ORA-06512: at line 1

I will do tests on 11G Release 2 once it is available for download on Solaris version.
But, from the document of 11G Release 2, which has been already available, there is still
no such function in such as set_index_prefs provided.



3. Under the hood
3.1 Where the synopsis exists?
As it is said in part 1, it is in sysaux tablespace:
SQL> select OCCUPANT_NAME, OCCUPANT_DESC, SPACE_USAGE_KBYTES/power(1024,2) from
v$sysaux_occupants order by 2;

OCCUPANT_NAME          OCCUPANT_DESC                                           SPAC
E_USAGE_KBYTES/POWER(1024,2)
--------------------- ---------------------------------------------------- ----
----------------------------
AO                     Analytical Workspace Object
Table                                            .001342773
AUTO_TASK              Automated Maintenance
Tasks                                                  .000305176
EM_MONITORING_USER     Enterprise Manager Monitoring
User                                           .001647949
LOGMNR                 LogMiner
                   .007385254
LOGSTDBY               Logical
Standby                                                                .000976563
XSOQHIST               OLAP API History
Tables                                                       .001342773
STREAMS                Oracle
Streams                                                                 .000976563
TSM                    Oracle Transparent Session Migration
User                                    .000244141
PL/SCOPE               PL/SQL Identifier
Collection                                                  .000366211
SQL_MANAGEMENT_BASE    SQL Management Base
Schema                                                    .001647949
SM/ADVISOR                  Server Manageability - Advisor
Framework                                           .016052246
SM/AWR                      Server Manageability - Automatic Workload
Repository                              .125610352
SM/OPTSTAT                  Server Manageability - Optimizer Statistics
History                              .115722656
SM/OTHER                    Server Manageability - Other
Components                                             .00567627
SMON_SCN_TIME               Transaction Layer - SCN to TIME
mapping                                            .003173828
JOB_SCHEDULER               Unified Job
Scheduler                                                             .000610352

29 rows selected.

The blue line represents the space occupied by the synopsis for global level statistics.
Usually, it will only consume very little space.

Using sql_trace, found that the attribute for incremental for a table is stored in table
SYS.OPTSTAT_USER_PREF$:

SQL> select a.obj#, name, pname, valchar from SYS.OPTSTAT_USER_PREFS$ a, obj$ b
where a.obj# = b.obj#;

      OBJ# NAME                           PNAME                VALCHAR
---------- ------------------------------ -------------------- ----------------
     15307 TEST_INC                       INCREMENTAL          TRUE


In fact, for a partitioned table, the global level “NDV” (Number of Distinct Value) of
                                                    NDV”
columns is the most challengeable. All other statistics can be speculated from partition
level, such as num_rows, blocks, avg_row_len. So, I think, this is what Oracle 11G Release
2 enhances.



4. My conclusion:
I think, incremental statistics gathering for partitioned tables is a very useful new feature
introduced by ORACLE 11G if all the bugs can be resolved.
It will consume much less resource especially for large partitioned/subpartitioned tables
and shorten our statistics gathering process. I believe it will
not only help us for our normal analyze CR, but also it will help us under situations under
tough situations (such as TCB) caused by inaccurate statistics,
as at such situations, time is so precious for us.

Anyway, I will track this feature.

Thanks!

More Related Content

Similar to Incremental statistics for partitioned tables in 11g by wwf from ebay COC

Sip _ready_reckoner___compliance_approved
Sip  _ready_reckoner___compliance_approvedSip  _ready_reckoner___compliance_approved
Sip _ready_reckoner___compliance_approved
guestc7ba7d90
 
การวิจัยพฤติกรรมการบริโภคอาหารของนักศึกษามหาวิทยาลัยราชภัฎนครปฐม
การวิจัยพฤติกรรมการบริโภคอาหารของนักศึกษามหาวิทยาลัยราชภัฎนครปฐมการวิจัยพฤติกรรมการบริโภคอาหารของนักศึกษามหาวิทยาลัยราชภัฎนครปฐม
การวิจัยพฤติกรรมการบริโภคอาหารของนักศึกษามหาวิทยาลัยราชภัฎนครปฐม
Sutasinee Phu-on
 
Analysis update for GENEVA meeting 2011
Analysis update for GENEVA meeting 2011Analysis update for GENEVA meeting 2011
Analysis update for GENEVA meeting 2011
USC
 
Data Hasil Evaluasi Kelas Iii Sd N Merak
Data Hasil Evaluasi Kelas Iii Sd N MerakData Hasil Evaluasi Kelas Iii Sd N Merak
Data Hasil Evaluasi Kelas Iii Sd N Merak
guestd1077c
 
Nilai Kelas Iii Sd Merak
Nilai Kelas Iii Sd MerakNilai Kelas Iii Sd Merak
Nilai Kelas Iii Sd Merak
guestd1077c
 
Nilai Kelas Iii Sd Merak
Nilai Kelas Iii Sd MerakNilai Kelas Iii Sd Merak
Nilai Kelas Iii Sd Merak
guestd1077c
 
1 q10 presentation
1 q10 presentation1 q10 presentation
1 q10 presentation
SiteriCR2
 

Similar to Incremental statistics for partitioned tables in 11g by wwf from ebay COC (20)

Chapter 9
Chapter 9Chapter 9
Chapter 9
 
Profiling blueprints
Profiling blueprintsProfiling blueprints
Profiling blueprints
 
ARitificial Intelligence - Project - Data Classification
ARitificial Intelligence - Project - Data ClassificationARitificial Intelligence - Project - Data Classification
ARitificial Intelligence - Project - Data Classification
 
Lacture 8 market research
Lacture 8 market researchLacture 8 market research
Lacture 8 market research
 
AA-sort with SSE4.1
AA-sort with SSE4.1AA-sort with SSE4.1
AA-sort with SSE4.1
 
Sip _ready_reckoner___compliance_approved
Sip  _ready_reckoner___compliance_approvedSip  _ready_reckoner___compliance_approved
Sip _ready_reckoner___compliance_approved
 
การวิจัยพฤติกรรมการบริโภคอาหารของนักศึกษามหาวิทยาลัยราชภัฎนครปฐม
การวิจัยพฤติกรรมการบริโภคอาหารของนักศึกษามหาวิทยาลัยราชภัฎนครปฐมการวิจัยพฤติกรรมการบริโภคอาหารของนักศึกษามหาวิทยาลัยราชภัฎนครปฐม
การวิจัยพฤติกรรมการบริโภคอาหารของนักศึกษามหาวิทยาลัยราชภัฎนครปฐม
 
Visualizing Dynamic Metrics with Profiling Blueprints
Visualizing Dynamic Metrics with Profiling BlueprintsVisualizing Dynamic Metrics with Profiling Blueprints
Visualizing Dynamic Metrics with Profiling Blueprints
 
Chebyshevs
ChebyshevsChebyshevs
Chebyshevs
 
(ATS4-PLAT07) Interactive Charts Revamped
(ATS4-PLAT07) Interactive Charts Revamped(ATS4-PLAT07) Interactive Charts Revamped
(ATS4-PLAT07) Interactive Charts Revamped
 
Bolt details
Bolt detailsBolt details
Bolt details
 
FULL TIME SUPPORT QUOTAS MARCH 2011
FULL TIME SUPPORT QUOTAS MARCH 2011FULL TIME SUPPORT QUOTAS MARCH 2011
FULL TIME SUPPORT QUOTAS MARCH 2011
 
Analysis update for GENEVA meeting 2011
Analysis update for GENEVA meeting 2011Analysis update for GENEVA meeting 2011
Analysis update for GENEVA meeting 2011
 
Data Hasil Evaluasi Kelas Iii Sd N Merak
Data Hasil Evaluasi Kelas Iii Sd N MerakData Hasil Evaluasi Kelas Iii Sd N Merak
Data Hasil Evaluasi Kelas Iii Sd N Merak
 
AA-I & Co. | Simple labor-category Price Curve Model
AA-I & Co. | Simple labor-category Price Curve ModelAA-I & Co. | Simple labor-category Price Curve Model
AA-I & Co. | Simple labor-category Price Curve Model
 
Nilai Kelas Iii Sd Merak
Nilai Kelas Iii Sd MerakNilai Kelas Iii Sd Merak
Nilai Kelas Iii Sd Merak
 
Nilai Kelas Iii Sd Merak
Nilai Kelas Iii Sd MerakNilai Kelas Iii Sd Merak
Nilai Kelas Iii Sd Merak
 
1 q10 presentation
1 q10 presentation1 q10 presentation
1 q10 presentation
 
ธนาคารกสิกรไทย
ธนาคารกสิกรไทย ธนาคารกสิกรไทย
ธนาคารกสิกรไทย
 
Towards Probabilistic Assessment of Modularity
Towards Probabilistic Assessment of ModularityTowards Probabilistic Assessment of Modularity
Towards Probabilistic Assessment of Modularity
 

More from Louis liu

基于Mongodb的压力评测工具 ycsb的一些概括
基于Mongodb的压力评测工具 ycsb的一些概括基于Mongodb的压力评测工具 ycsb的一些概括
基于Mongodb的压力评测工具 ycsb的一些概括
Louis liu
 
NetApp ef540 SSD Storage Test
NetApp ef540 SSD Storage TestNetApp ef540 SSD Storage Test
NetApp ef540 SSD Storage Test
Louis liu
 
MySQL 5.5&5.6 new features summary
MySQL 5.5&5.6 new features summaryMySQL 5.5&5.6 new features summary
MySQL 5.5&5.6 new features summary
Louis liu
 
Ssd gc review
Ssd gc reviewSsd gc review
Ssd gc review
Louis liu
 
1号店数据库架构
1号店数据库架构1号店数据库架构
1号店数据库架构
Louis liu
 
Architecture of YHD
Architecture of YHDArchitecture of YHD
Architecture of YHD
Louis liu
 

More from Louis liu (20)

Tcpcopy benchmark
Tcpcopy benchmarkTcpcopy benchmark
Tcpcopy benchmark
 
JK Log-Center architect
JK Log-Center architectJK Log-Center architect
JK Log-Center architect
 
Wdt Test
Wdt TestWdt Test
Wdt Test
 
JKDB BACKUP Introduction
JKDB BACKUP IntroductionJKDB BACKUP Introduction
JKDB BACKUP Introduction
 
Infiniflash benchmark
Infiniflash benchmarkInfiniflash benchmark
Infiniflash benchmark
 
MySQL Tokudb engine benchmark
MySQL Tokudb engine benchmarkMySQL Tokudb engine benchmark
MySQL Tokudb engine benchmark
 
Nvmfs benchmark
Nvmfs benchmarkNvmfs benchmark
Nvmfs benchmark
 
MySQL 5.7 milestone
MySQL 5.7 milestoneMySQL 5.7 milestone
MySQL 5.7 milestone
 
MySQL Oslayer performace optimization
MySQL  Oslayer performace optimizationMySQL  Oslayer performace optimization
MySQL Oslayer performace optimization
 
MySQL async message subscription platform
MySQL async message subscription platformMySQL async message subscription platform
MySQL async message subscription platform
 
HBASE Performane Test
HBASE Performane TestHBASE Performane Test
HBASE Performane Test
 
Jkcn MySQLDB 架构
Jkcn MySQLDB 架构Jkcn MySQLDB 架构
Jkcn MySQLDB 架构
 
基于Mongodb的压力评测工具 ycsb的一些概括
基于Mongodb的压力评测工具 ycsb的一些概括基于Mongodb的压力评测工具 ycsb的一些概括
基于Mongodb的压力评测工具 ycsb的一些概括
 
My sql fabric ha and sharding solutions
My sql fabric ha and sharding solutionsMy sql fabric ha and sharding solutions
My sql fabric ha and sharding solutions
 
NetApp ef540 SSD Storage Test
NetApp ef540 SSD Storage TestNetApp ef540 SSD Storage Test
NetApp ef540 SSD Storage Test
 
Exadata best practice on E-commerce area
Exadata best practice on E-commerce area Exadata best practice on E-commerce area
Exadata best practice on E-commerce area
 
MySQL 5.5&5.6 new features summary
MySQL 5.5&5.6 new features summaryMySQL 5.5&5.6 new features summary
MySQL 5.5&5.6 new features summary
 
Ssd gc review
Ssd gc reviewSsd gc review
Ssd gc review
 
1号店数据库架构
1号店数据库架构1号店数据库架构
1号店数据库架构
 
Architecture of YHD
Architecture of YHDArchitecture of YHD
Architecture of YHD
 

Incremental statistics for partitioned tables in 11g by wwf from ebay COC

  • 1. 1, what oracle document tells us? For partitioned tables, when we collect statistics, even when only one partition changed, such as add a new partition or load some data to a partition, we have to scan all partitions to compute global statistics, this is much resource intensive operation. In 11G, oracle introduced “incremental” statistics gather option for partitioned table. When a partitioned table is set to “incremental” attribute, it will store a synopsis on sysaux tablespace for global level statistics(it will only consume very little space), then, it will only scan one partition but will update the global statistics, which will save many resource. 2, my test: 2.0: My Test Environments: Oracle version is: 11.1.0.6, OS: Solaris 2.1 create test table: Let us create 2 tables test_inc(enable incremental statistics) and test_inc_bak(disable incremental statistics) with same structure: SQL> create table test_inc test_inc(a number, b date, c varchar2(30), d varchar2(100), e varchar2(100), partition_key number) 2 partition by range(partition_key) 3 ( 4 partition p00 values less than (1), 5 partition p01 values less than (2), 6 partition p02 values less than (3), 7 partition p03 values less than (4), 8 partition p04 values less than (5), 9 partition p05 values less than (6), 10 partition p06 values less than (7), 11 partition p07 values less than (8), 12 partition p08 values less than (9), 13 partition p09 values less than (10), 14 partition p10 values less than (11), 15 partition p11 values less than (12), 16 partition p12 values less than (13), 17 partition p13 values less than (14), 18 partition p14 values less than (15), 19 partition p15 values less than (16), 20 partition p16 values less than (17), 21 partition p17 values less than (18), 22 partition p18 values less than (19), 23 partition p19 values less than (20), 24 partition p20 values less than (21), 25 partition p21 values less than (22), 26 partition p22 values less than (23), 27 partition p23 values less than (24), 28 partition p24 values less than (25), 29 partition p25 values less than (26), 30 partition p26 values less than (27), 31 partition p27 values less than (28), 32 partition p28 values less than (29),
  • 2. 33 partition p29 values less than (30), 34 partition p30 values less than (31), 35 partition pmax values less than(maxvalue) 36 ) ; SQL> create table test_inc_bak test_inc_bak(a number, b date, c varchar2(30), d varchar2(100), e varchar2(100), partition_key number) 2 partition by range(partition_key) 3 ( 4 partition p00 values less than (1), 5 partition p01 values less than (2), 6 partition p02 values less than (3), 7 partition p03 values less than (4), 8 partition p04 values less than (5), 9 partition p05 values less than (6), 10 partition p06 values less than (7), 11 partition p07 values less than (8), 12 partition p08 values less than (9), 13 partition p09 values less than (10), 14 partition p10 values less than (11), 15 partition p11 values less than (12), 16 partition p12 values less than (13), 17 partition p13 values less than (14), 18 partition p14 values less than (15), 19 partition p15 values less than (16), 20 partition p16 values less than (17), 21 partition p17 values less than (18), 22 partition p18 values less than (19), 23 partition p19 values less than (20), 24 partition p20 values less than (21), 25 partition p21 values less than (22), 26 partition p22 values less than (23), 27 partition p23 values less than (24), 28 partition p24 values less than (25), 29 partition p25 values less than (26), 30 partition p26 values less than (27), 31 partition p27 values less than (28), 32 partition p28 values less than (29), 33 partition p29 values less than (30), 34 partition p30 values less than (31), 35 partition pmax values less than(maxvalue) 36 ); 2.2 set incremental attribute for one table: Let enable “incremental” statistics gathering for test_inc: SQL> select DBMS_STATS.get_PREFS('incremental', 'wwf', 'test_inc') from dual; DBMS_STATS.GET_PREFS('INCREMENTAL','WWF','TEST_INC') FALSE SQL> exec DBMS_STATS.SET_TABLE_PREFS(user,'test_inc','INCREMENTAL','TRUE') PL/SQL procedure successfully completed. SQL> select DBMS_STATS.get_PREFS('incremental', 'wwf', 'test_inc') from dual; DBMS_STATS.GET_PREFS('INCREMENTAL','WWF','TEST_INC')
  • 3. TRUE For test_inc_bak, keep it disabled for “incremental” statistics gathering: SQL> select DBMS_STATS.get_PREFS('incremental', 'wwf', 'test_inc_bak') from dual; DBMS_STATS.GET_PREFS('INCREMENTAL','WWF','TEST_INC_BAK') --------------------------------------------------------------------------------------------------------------------------------- FALSE 2.3 The whole test process: populate Then, using the following sql to populate data for each partition(populate 300k records for each partition and change the value of partition key correspondingly correspondingly): insert into test_inc select rownum, sysdate+mod(rownum, 30), 'wangweifengwangweifeng'||rownum, rpad('x', 50, 'x')||rownum, rpad('y', 50, 'z')||rownum, 0 from dual connect by rownum <= 300000 300000; insert into test_inc_bak select rownum, sysdate+mod(rownum, 30), 'wangweifengwangweifeng'||rownum, rpad('x', 50, 'x')||rownum, rpad('y', 50, 'z')||rownum, 0 from dual connect by rownum <= 300000 300000; My test indicates that: the “incremental” attribute will make the statistics gathering process much faster! exec dbms_stats.gather_table_stats(user, 'test_inc') exec dbms_stats.gather_table_stats(user, 'test_inc_bak') 2.4 test result and compare The following table is the time spent for incremental/non-incremental tables statistics-gathering process: partition Time elapsed for incremental table Time elapsed for non-incremental table number test_inc(seconds) test_inc(seconds seconds) test_inc_bak (seconds) seconds) 1 4.37 4.36 2 4.47 8.66 3 5.09 13.2 4 5.38 19.48 5 5.47 24.06 6 5.76 29.39 7 6.13 34.03 8 6.62 38.97 9 7.28 46.24 10 7.32 50.75 11 7.53 56.83 12 7.86 62.25 13 8.62 67.06 14 8.89 72.73 15 9.48 78.93 16 10.01 83.66 17 10.77 87.44
  • 4. 18 11.22 93.74 19 10.72 100.85 20 11.48 105.54 21 11.01 112.08 22 11.06 116.53 23 10.68 123.57 24 12.58 126.58 25 8.01 135.41 26 12.38 137.95 27 13.09 144.33 28 14.67 149.75 29 13.55 153.94 30 14.27 160.50 31 14.15 165.50 Use the above data, let’s plot picture: let’ We can see, for non-incremental partitioned table, the time elapsed for non-incremental (the yellow line) is linear with the partition number. While for the incremental partitioned table, the time elapsed (the red line) is nearly a flat line: The red line represent time elapsed for incremental partitioned table The yellow line time elapsed for non-incremental partitioned table
  • 5. 2.5: let’s see from another perspective: what last_analyzed column can tell let’ us? SQL> exec dbms_stats.gather_table_stats(user, 'test_inc' 'test_inc') PL/SQL procedure successfully completed. Elapsed: 00:00:04.37 SQL> select partition_name, blocks, num_rows, last_analyzed from user_tab_partitions where table_name = 'TEST_INC' and num_rows > 0; PARTITION_NAME BLOCKS NUM_ROWS LAST_ANALYZED ------------------------------ ---------- ---------- ------------------- P00 6796 300000 2009-09-09 00:49:51 SQL> select table_name, blocks, num_rows, last_analyzed from user_tables where table_name = 'TEST_INC'; TABLE_NAME BLOCKS NUM_ROWS LAST_ANALYZED ------------------------------ ---------- ---------- ------------------- TEST_INC 6796 300000 2009-09-09 00:49:51 Insert 300k records for empty partition p2: SQL> exec dbms_stats.gather_table_stats(user, 'test_inc') PL/SQL procedure successfully completed. Elapsed: 00:00:04.47 SQL> select partition_name, blocks, num_rows, last_analyzed from user_tab_partitions where table_name = 'TEST_INC' and num_rows > 0; PARTITION_NAME BLOCKS NUM_ROWS LAST_ANALYZED ------------------------------ ---------- ---------- ------------------- P00 6796 300000 2009-09-09 00:49:51 P01 6796 300000 2009-09-09 00:52:27 SQL> select table_name, blocks, num_rows, last_analyzed from user_tables where table_name = 'TEST_INC'; TABLE_NAME BLOCKS NUM_ROWS LAST_ANALYZED ------------------------------ ---------- ---------- ------------------- TEST_INC 13592 600000 2009-09-09 00:52:29 Insert 300k records for empty partition p3: SQL> exec dbms_stats.gather_table_stats(user, 'test_inc') PL/SQL procedure successfully completed. Elapsed: 00:00:05.09 SQL> select partition_name, blocks, num_rows, last_analyzed from user_tab_partitions where table_name = 'TEST_INC' and num_rows > 0; PARTITION_NAME BLOCKS NUM_ROWS LAST_ANALYZED ------------------------------ ---------- ---------- ------------------- P00 6796 300000 2009-09-09 00:49:51 P01 6796 300000 2009-09-09 00:52:27 P02 6796 300000 2009-09-09 00:55:39
  • 6. SQL> select table_name, blocks, num_rows, last_analyzed from user_tables where table_name = 'TEST_INC'; TABLE_NAME BLOCKS NUM_ROWS LAST_ANALYZED ------------------------------ ---------- ---------- ------------------- TEST_INC 20388 900000 2009-09-09 00:55:40 Insert 300k records for empty partition p4: SQL> exec dbms_stats.gather_table_stats(user, 'test_inc') PL/SQL procedure successfully completed. Elapsed: 00:00:05.38 SQL> select partition_name, blocks, num_rows, last_analyzed from user_tab_partitions where table_name = 'TEST_INC' 2 and num_rows > 0; PARTITION_NAME BLOCKS NUM_ROWS LAST_ANALYZED ------------------------------ ---------- ---------- ------------------- P00 6796 300000 2009-09-09 00:49:51 P01 6796 300000 2009-09-09 00:52:27 P02 6796 300000 2009-09-09 00:55:39 P03 6796 300000 2009-09-09 01:00:23 SQL> select table_name, blocks, num_rows, last_analyzed from user_tables where table_name = 'TEST_INC'; TABLE_NAME BLOCKS NUM_ROWS LAST_ANALYZED ------------------------------ ---------- ---------- ------------------- TEST_INC 27184 1200000 2009-09-09 01:00:24 We can see that: the last_analyzed column won’t change after each analyze. won’ This can tell us that: the unchanged analyzed partition is skipped when enable incremental statistics gathering. But, let’s see the last_analyzed column for non-incremental partitions table: let’ The last_analyze column changes when every analyze: this is the last time I analyzed the non-incremental table test_inc_bak(I started my test from 09/09/2009): SQL> select partition_name, num_rows, blocks, last_analyzed from user_tab_partitions where table_name = 'TEST_INC_BAK' 'TEST_INC_BAK'; PARTITION_NAME NUM_ROWS BLOCKS LAST_ANALYZED ------------------------------ ---------- ---------- ------------------- P00 300000 6796 2009-09-11 01:07:43 P01 300000 6796 2009-09-11 01:07:46 P02 300000 6796 2009-09-11 01:07:49 P03 300000 6796 2009-09-11 01:07:52 P04 300000 6796 2009-09-11 01:07:54 P05 300000 6796 2009-09-11 01:07:57 P06 300000 6796 2009-09-11 01:08:00 P07 300000 6796 2009-09-11 01:08:03 P08 300000 6796 2009-09-11 01:08:06 P09 300000 6796 2009-09-11 01:08:09 P10 300000 6796 2009-09-11 01:08:13 P11 300000 6796 2009-09-11 01:08:16 P12 300000 6796 2009-09-11 01:08:19 P13 300000 6796 2009-09-11 01:08:22 P14 300000 6796 2009-09-11 01:08:24 P15 300000 6796 2009-09-11 01:08:27
  • 7. P16 300000 6796 2009-09-11 01:08:30 P17 300000 6796 2009-09-11 01:08:33 P18 300000 6796 2009-09-11 01:08:36 P19 300000 6796 2009-09-11 01:08:39 P20 300000 6796 2009-09-11 01:08:42 P21 300000 6796 2009-09-11 01:08:45 P22 300000 6796 2009-09-11 01:08:48 P23 300000 6796 2009-09-11 01:08:51 P24 300000 6796 2009-09-11 01:08:54 P25 300000 6796 2009-09-11 01:08:57 P26 300000 6796 2009-09-11 01:09:00 P27 300000 6796 2009-09-11 01:09:03 P28 300000 6796 2009-09-11 01:09:06 P29 300000 6796 2009-09-11 01:09:09 P30 300000 6796 2009-09-11 01:09:11 PMAX 0 0 2009-09-11 01:09:11 While the following is what analyze looks like when I finish the analyze on incremental table test_inc_bak: SQL> select partition_name, num_rows, blocks, last_analyzed from user_tab_partitions where table_name = 'TEST_INC''TEST_INC'; PARTITION_NAME NUM_ROWS BLOCKS LAST_ANALYZED ------------------------------ ---------- ---------- ------------------- P00 300000 6796 2009-09-09 00:49:51 P01 300000 6796 2009-09-09 00:52:27 P02 300000 6796 2009-09-09 00:55:39 P03 300000 6796 2009-09-09 01:00:23 P04 300000 6796 2009-09-09 01:04:59 P05 300000 6796 2009-09-09 01:09:37 P06 300000 6796 2009-09-09 01:14:06 P07 300000 6796 2009-09-09 01:17:33 P08 300000 6796 2009-09-09 01:22:14 P09 300000 6796 2009-09-09 01:28:15 P10 300000 6796 2009-09-09 01:33:29 P11 300000 6796 2009-09-09 01:36:36 P12 300000 6796 2009-09-09 01:42:39 P13 300000 6796 2009-09-09 01:46:54 P14 300000 6796 2009-09-09 01:55:36 P15 300000 6796 2009-09-09 02:04:55 P16 300000 6796 2009-09-09 02:20:34 P17 300000 6796 2009-09-09 03:05:48 P18 300000 6796 2009-09-09 03:38:40 P19 300000 6796 2009-09-09 04:10:07 P20 300000 6796 2009-09-09 04:14:57 P21 300000 6796 2009-09-09 04:46:03 P22 300000 6796 2009-09-09 04:57:09 P23 300000 6796 2009-09-09 05:28:45 P24 300000 6796 2009-09-11 22:03:14 P25 300000 6796 2009-09-11 00:31:14 P26 300000 6796 2009-09-11 00:37:14 P27 300000 6796 2009-09-11 00:44:13 P28 300000 6796 2009-09-11 00:52:49 P29 300000 6796 2009-09-11 01:00:16 P30 300000 6796 2009-09-11 01:06:34 PMAX 0 0 2009-09-11 01:06:34 2.6 The drawback or bugs of incremental statistics: 2.6.1: It is only sensitive for newly load data partition:
  • 8. Per my test, it seems that, “incremental statistics” is only sensitive for a new partition which is completely newly loaded data. It can be aware of the following situations: a. delete/insert some data to a partition that has already been analyzed b. truncate one/more partitions Please see my test: The table currently has 1.8 million records, each partition contain 0.3 million records: SQL> select partition_name, num_rows, blocks, last_analyzed from user_tab_partitions where table_name = 'TEST_INC' and num_rows > 0; PARTITION_NAME NUM_ROWS BLOCKS LAST_ANALYZED ------------------------------ ---------- ---------- ------------------- P00 300000 6796 2009-09-12 01:41:56 P01 300000 6796 2009-09-12 01:45:07 P02 300000 6796 2009-09-12 01:47:11 P03 300000 6796 2009-09-12 01:50:11 P04 300000 6796 2009-09-12 01:51:41 P05 300000 6796 2009-09-12 01:52:48 Delete 100k records for partition p05: SQL> delete from test_inc partition(p05) where rownum <= 100000; 100000 rows deleted. Truncate partition p04: SQL> alter table test_inc truncate partition p04 ; Table truncated. Insert 100k records to partition p01: SQL> insert into test_inc select rownum, sysdate+mod(rownum, 30), 'wangweifengwangweifeng'||rownum, 2 rpad('x', 50, 'x')||rownum, rpad('y', 50, 'z')||rownum, 1 from dual connect by rownum <= 300000; 300000 rows created. But, let us analyze it: SQL> exec dbms_stats.gather_table_stats(user, 'test_inc'); PL/SQL procedure successfully completed. SQL> select table_name, num_rows, blocks, last_analyzed from user_tables where table_name = 'TEST_INC'; TABLE_NAME NUM_ROWS BLOCKS LAST_ANALYZED ------------------------------ ---------- ---------- ------------------- TEST_INC 1800000 41361 2009-09-12 01:57:21 SQL> select partition_name, num_rows, blocks, last_analyzed from user_tab_partitions where table_name = 'TEST_INC' and num_rows > 0; PARTITION_NAME NUM_ROWS BLOCKS LAST_ANALYZED ------------------------------ ---------- ---------- ------------------- P00 300000 6796 2009-09-12 01:41:56 P01 300000 6796 2009-09-12 01:45:07 P02 300000 6796 2009-09-12 01:47:11
  • 9. P03 300000 6796 2009-09-12 01:50:11 P04 300000 6796 2009-09-12 01:51:41 P05 300000 6796 2009-09-12 01:52:48 6 rows selected. SQL> select count(*) from test_inc partition(p05); COUNT(*) ---------- 200000 SQL> select count(*) from test_inc partition(p06); COUNT(*) ---------- 0 SQL> select count(*) from test_inc partition(p01); COUNT(*) ---------- 600000 We can see, the statistics does not change at all! Then, will it triggered by populating data into a newly loaded partition? It won’t! Let me insert data to an empty partition p06: won’ SQL> insert into test_inc select rownum, sysdate+mod(rownum, 30), 'wangweifengwangweifeng'||rownum, 2 rpad('x', 50, 'x')||rownum, rpad('y', 50, 'z')||rownum, 6 from dual connect by rownum <= 300000; 300000 rows created. SQL> exec dbms_stats.gather_table_stats(user, 'test_inc'); PL/SQL procedure successfully completed. Elapsed: 00:00:06.61 SQL> select table_name, num_rows, blocks, last_analyzed from user_tables where table_name = 'TEST_INC'; TABLE_NAME NUM_ROWS BLOCKS LAST_ANALYZED ------------------------------ ---------- ---------- ------------------- TEST_INC 2100000 48157 2009-09-12 02:01:36 SQL> select partition_name, num_rows, blocks, last_analyzed from user_tab_partitions where table_name = 'TEST_INC' and num_rows > 0; PARTITION_NAME NUM_ROWS BLOCKS LAST_ANALYZED ------------------------------ ---------- ---------- ------------------- P00 300000 6796 2009-09-12 01:41:56 P01 300000 6796 2009-09-12 01:45:07 P02 300000 6796 2009-09-12 01:47:11 P03 300000 6796 2009-09-12 01:50:11 P04 300000 6796 2009-09-12 01:51:41 P05 300000 6796 2009-09-12 01:52:48
  • 10. P06 300000 6796 2009-09-12 02:01:33 7 rows selected. How about I truncate all tables? Let me initialize the table and populate 2.1 million records for 7 partitions: SQL> select table_name, num_rows, blocks, last_analyzed from user_tables where table_name = 'TEST_INC'; TABLE_NAME NUM_ROWS BLOCKS LAST_ANALYZED ------------------------------ ---------- ---------- ------------------- TEST_INC 2100000 47572 2009-09-12 04:05:18 SQL> select partition_name, num_rows, blocks, last_analyzed from user_tab_partitions where table_name = 'TEST_INC' and num_rows > 0; PARTITION_NAME NUM_ROWS BLOCKS LAST_ANALYZED ------------------------------ ---------- ---------- ------------------- P00 300000 6796 2009-09-12 03:53:58 P01 300000 6796 2009-09-12 03:54:42 P02 300000 6796 2009-09-12 03:55:24 P03 300000 6796 2009-09-12 04:01:54 P04 300000 6796 2009-09-12 04:03:33 P05 300000 6796 2009-09-12 04:04:26 P06 300000 6796 2009-09-12 04:05:16 7 rows selected. SQL> truncate table test_inc; Table truncated. Elapsed: 00:00:02.24 SQL> exec dbms_stats.gather_table_stats(user, 'test_inc'); PL/SQL procedure successfully completed. Elapsed: 00:00:00.61 SQL> select table_name, num_rows, blocks, last_analyzed from user_tables where table_name = 'TEST_INC'; TABLE_NAME NUM_ROWS BLOCKS LAST_ANALYZED ------------------------------ ---------- ---------- ------------------- TEST_INC 0 0 2009-09-12 04:09:43 SQL> select partition_name, num_rows, blocks, last_analyzed from user_tab_partitions where table_name = 'TEST_INC' and num_rows > 0; PARTITION_NAME NUM_ROWS BLOCKS LAST_ANALYZED ------------------------------ ---------- ---------- ------------------- P00 300000 6796 2009-09-12 03:53:58 P01 300000 6796 2009-09-12 03:54:42 P02 300000 6796 2009-09-12 03:55:24 P03 300000 6796 2009-09-12 04:01:54 P04 300000 6796 2009-09-12 04:03:33 P05 300000 6796 2009-09-12 04:04:26 P06 300000 6796 2009-09-12 04:05:16 7 rows selected.
  • 11. We can see: the statistics for table level is got updated, but, it is not got updated for partition level! I think, it should be a bug! Anyway, I will file TAR for Oracle for clarify. How to fix it temporarily? Set it back to “no-incremental”, then analyze again: no-incremental” SQL> exec DBMS_STATS.SET_TABLE_PREFS(user,'test_inc','INCREMENTAL','FALSE' 'FALSE' 'FALSE'); PL/SQL procedure successfully completed. SQL> select DBMS_STATS.get_PREFS('incremental', 'wwf', 'test_inc') from dual; DBMS_STATS.GET_PREFS('INCREMENTAL','WWF','TEST_INC') ----------------------------------------------------------------------- FALSE SQL> exec dbms_stats.gather_table_stats(user, 'test_inc'); PL/SQL procedure successfully completed. SQL> select partition_name, num_rows, blocks, last_analyzed from user_tab_partitions where table_name = 'TEST_INC' and num_rows > 0; no rows selected SQL> select table_name, num_rows, blocks, last_analyzed from user_tables where table_name = 'TEST_INC'; TABLE_NAME NUM_ROWS BLOCKS LAST_ANALYZED ------------------------------ ---------- ---------- ------------------- TEST_INC 0 0 2009-09-12 04:18:34 SQL> select partition_name, num_rows, blocks, last_analyzed from user_tab_partitions where table_name = 'TEST_INC'; PARTITION_NAME NUM_ROWS BLOCKS LAST_ANALYZED ------------------------------ ---------- ---------- ------------------- P00 0 0 2009-09-12 04:18:34 P01 0 0 2009-09-12 04:18:34 P02 0 0 2009-09-12 04:18:34 P03 0 0 2009-09-12 04:18:34 P04 0 0 2009-09-12 04:18:34 P05 0 0 2009-09-12 04:18:34 P06 0 0 2009-09-12 04:18:34 P07 0 0 2009-09-12 04:18:34 2.6.2 For subpartition table, it is totally wrong: SQL> CREATE TABLE composite_rng_list ( 2 cust_id NUMBER(10), 3 cust_name VARCHAR2(25), 4 cust_state VARCHAR2(2), 5 time_id DATE) 6 PARTITION BY RANGE(time_id) 7 SUBPARTITION BY LIST (cust_state) 8 SUBPARTITION TEMPLATE( 9 SUBPARTITION west VALUES ('OR', 'WA'),
  • 12. 10 SUBPARTITION east VALUES ('NY', 'CT'), 11 SUBPARTITION cent VALUES ('OK', 'TX')) ( 12 PARTITION per1 VALUES LESS THAN (TO_DATE('01/01/2008','DD/MM/YYYY')), 13 PARTITION per2 VALUES LESS THAN (TO_DATE('01/01/2010','DD/MM/YYYY')), 14 PARTITION per3 VALUES LESS THAN (TO_DATE('01/01/2012','DD/MM/YYYY')), 15 PARTITION future VALUES LESS THAN(MAXVALUE)); Table created. SQL> exec dbms_stats.set_table_prefs('wwf', 'composite_rng_list', 'incremental', 'true') PL/SQL procedure successfully completed. Elapsed: 00:00:00.01 SQL> select dbms_stats.get_prefs('incremental', 'wwf', 'composite_rng_list') from dual; DBMS_STATS.GET_PREFS('INCREMENTAL','WWF','COMPOSITE_RNG_LIST') --------------------------------------------------------------------- TRUE SQL> insert into composite_rng_list select rownum, 'customer'||rownum, 'OR', to_date('2007-01-01', 'yyyy-mm-dd') from dual connect by rownum <= 100000; 100000 rows created. SQL> commit; Commit complete. SQL> select table_name, num_rows, blocks, last_analyzed from user_tables where table_name = 'COMPOSITE_RNG_LIST'; TABLE_NAME NUM_ROWS BLOCKS LAST_ANALYZED ------------------------------ ---------- ---------- ------------------- COMPOSITE_RNG_LIST 100000 496 2009-09-14 18:17:58 Elapsed: 00:00:00.01 SQL> select partition_name, num_rows, blocks, last_analyzed from user_tab_partitions where table_name = 'COMPOSITE_RNG_LIST' and rownum > 0; PARTITION_NAME NUM_ROWS BLOCKS LAST_ANALYZED ---------------- ---------- ---------- ------------------- PER1 100000 496 2009-09-14 18:17:57 Elapsed: 00:00:00.00 SQL> select partition_name, SUBPARTITION_NAME, num_rows, blocks, last_analyzed from user_tab_subpartitions where table_name = 'COMPOSITE_RNG_LIST' and rownum > 0; PARTITION_NAME SUBPARTITION_NAME NUM_ROWS BLOCKS LAST_ANALYZED ---------------- ---------------- ---------- ---------- ------------------- PER1 PER1_WEST 100000 496 2009-09-14 18:17:55 Then, insert 100000 more rows and analyze again, we can see that, the statistics at partition level and table level were not changed at all: SQL> insert into composite_rng_list select rownum, 'customer'||rownum, 'WA', to_date('2007-01-01', 'yyyy-mm-dd') from dual connect by rownum <= 100000;
  • 13. 100000 rows created. SQL> commit; Commit complete. SQL> exec dbms_stats.gather_table_stats(user, 'COMPOSITE_RNG_LIST', granularity=>'ALL') PL/SQL procedure successfully completed. SQL> select table_name, num_rows, blocks, last_analyzed from user_tables where table_name = 'COMPOSITE_RNG_LIST'; TABLE_NAME NUM_ROWS BLOCKS LAST_ANALYZED ------------------------------ ---------- ---------- ------------------- COMPOSITE_RNG_LIST 100000 1000 2009-09-14 18:24:12 SQL> select partition_name, num_rows, blocks, last_analyzed from user_tab_partitions where table_name = 'COMPOSITE_RNG_LIST' and num_rows > 0; PARTITION_NAME NUM_ROWS BLOCKS LAST_ANALYZED ------------------------------ ---------- ---------- ------------------- PER1 100000 496 2009-09-14 18:17:57 SQL> select partition_name, SUBPARTITION_NAME, num_rows, blocks, last_analyzed from user_tab_subpartitions where table_name = 'COMPOSITE_RNG_LIST' and num_rows > 0; PARTITION_NAME SUBPARTITION_NAME NUM_ROWS BLOCKS LAST_ANALYZED --------------- -------------- ---------- ---------- ------------------- PER1 PER1_WEST 200000 1000 2009-09-14 18:24:11 Then, insert 100000 more rows and analyze again, we can see that, the statistics at partition level and table level were not changed at all: SQL> insert into composite_rng_list select rownum, 'customer'||rownum, 'NY', to_date('2007-01-01', 'yyyy-mm-dd') from dual connect by rownum <= 100000; 100000 rows created. SQL> commit; Commit complete. SQL> exec dbms_stats.gather_table_stats(user, 'COMPOSITE_RNG_LIST', granularity=>'ALL') PL/SQL procedure successfully completed. SQL> select table_name, num_rows, blocks, last_analyzed from user_tables where table_name = 'COMPOSITE_RNG_LIST'; TABLE_NAME NUM_ROWS BLOCKS LAST_ANALYZED ------------------------------ ---------- ---------- ------------------- COMPOSITE_RNG_LIST 100000 1496 2009-09-14 18:26:33 SQL> select partition_name, num_rows, blocks, last_analyzed from user_tab_partitions where table_name = 'COMPOSITE_RNG_LIST' and num_rows > 0; PARTITION_NAME NUM_ROWS BLOCKS LAST_ANALYZED ----------------- ---------- ---------- ------------------- PER1 100000 496 2009-09-14 18:17:57
  • 14. SQL> select partition_name, SUBPARTITION_NAME, num_rows, blocks, last_analyzed from user_tab_subpartitions where table_name = 'COMPOSITE_RNG_LIST' and num_rows > 0; PARTITION_NAME SUBPARTITION_NAME NUM_ROWS BLOCKS LAST_ANALYZED ------------ ----------------- ---------- ---------- ------------------- PER1 PER1_WEST 200000 1000 2009-09-14 18:26:32 PER1 PER1_EAST 100000 496 2009-09-14 18:26:32 Also, I do more test on subpartitione table. It can not display accurate statistics on partition level and table level. 2.6.3 There is no incremental statistics for partitioned indexes on partitioned tables: On the partitioned table in 2.1, we create a local partitioned index: SQL> create index ind_test_inc on test_inc(a) local; Index created. Insert 300k rows, then analyze: SQL> select partition_name, num_rows, DISTINCT_KEYS, clustering_factor, last_analyzed from user_ind_partitions where index_name = 'IND_TEST_INC' and num_rows > 0; PARTITION_NAME NUM_ROWS DISTINCT_KEYS CLUSTERING_FACTOR LAST_ANALYZED --------------- --------- ------------- ----------------- ------------------ P00 300000 300000 6763 2009-09-14 19:43:01 Insert 300k rows, then analyze: SQL> select partition_name, num_rows, DISTINCT_KEYS, clustering_factor, last_analyzed from user_ind_partitions where index_name = 'IND_TEST_INC' and num_rows > 0; PARTITION_NAME NUM_ROWS DISTINCT_KEYS CLUSTERING LAST_ANALYZED FACTOR ------------- ---------- ------------- ----------------- -------------- P00 300000 300000 6763 2009-09-14 19:54:35 P01 300000 300000 6763 2009-09-14 19:54:35 Insert 300k rows, then, analyze: SQL> select num_rows, DISTINCT_KEYS, clustering_factor, last_analyzed from user_indexes where index_name = 'IND_TEST_INC'; NUM_ROWS DISTINCT_KEYS CLUSTERING_FACTOR LAST_ANALYZED ---------- ------------- ----------------- ------------------- 900000 302976 20289 2009-09-14 20:00:50 SQL> select partition_name, num_rows, DISTINCT_KEYS, clustering_factor, last_analyzed from user_ind_partitions where index_name = 'IND_TEST_INC' and num_rows > 0; PARTITION_NAME NUM_ROWS DISTINCT_KEYS CLUSTERING_FACTOR LAST_ANALYZED --------------- ---------- ------------- ----------------- ------------------- P00 300000 300000 6763 2009-09-14 20:00:50 P01 300000 300000 6763 2009-09-14 20:00:50 P02 300000 300000 6763 2009-09-14 20:00:50 It seems that there is no way to set index “ind_test_inc” as incremental: ind_test_inc” SQL> select dbms_stats.get_prefs('incremental', 'wwf', 'test_inc') from dual; DBMS_STATS.GET_PREFS('INCREMENTAL','WWF','TEST_INC')
  • 15. -------------------------------------------- TRUE Elapsed: 00:00:00.01 SQL> select dbms_stats.get_prefs('incremental', 'wwf', 'ind_test_inc' from 'ind_test_inc') dual; DBMS_STATS.GET_PREFS('INCREMENTAL','WWF','IND_TEST_INC') ----------------------------------------------- FALSE Elapsed: 00:00:00.01 SQL> exec dbms_stats.set_table_prefs('wwf', 'ind_test_inc' 'incremental', 'ind_test_inc', 'true') BEGIN dbms_stats.set_table_prefs('wwf', 'ind_test_inc', 'incremental', 'true'); END; * ERROR at line 1: ORA-20000: TABLE "WWF"."IND_TEST_INC" does not exist or insufficient privileges ORA-06512: at "SYS.DBMS_STATS", line 2091 ORA-06512: at "SYS.DBMS_STATS", line 24110 ORA-06512: at line 1 I will do tests on 11G Release 2 once it is available for download on Solaris version. But, from the document of 11G Release 2, which has been already available, there is still no such function in such as set_index_prefs provided. 3. Under the hood 3.1 Where the synopsis exists? As it is said in part 1, it is in sysaux tablespace: SQL> select OCCUPANT_NAME, OCCUPANT_DESC, SPACE_USAGE_KBYTES/power(1024,2) from v$sysaux_occupants order by 2; OCCUPANT_NAME OCCUPANT_DESC SPAC E_USAGE_KBYTES/POWER(1024,2) --------------------- ---------------------------------------------------- ---- ---------------------------- AO Analytical Workspace Object Table .001342773 AUTO_TASK Automated Maintenance Tasks .000305176 EM_MONITORING_USER Enterprise Manager Monitoring User .001647949 LOGMNR LogMiner .007385254 LOGSTDBY Logical Standby .000976563 XSOQHIST OLAP API History Tables .001342773 STREAMS Oracle Streams .000976563 TSM Oracle Transparent Session Migration User .000244141 PL/SCOPE PL/SQL Identifier Collection .000366211 SQL_MANAGEMENT_BASE SQL Management Base Schema .001647949
  • 16. SM/ADVISOR Server Manageability - Advisor Framework .016052246 SM/AWR Server Manageability - Automatic Workload Repository .125610352 SM/OPTSTAT Server Manageability - Optimizer Statistics History .115722656 SM/OTHER Server Manageability - Other Components .00567627 SMON_SCN_TIME Transaction Layer - SCN to TIME mapping .003173828 JOB_SCHEDULER Unified Job Scheduler .000610352 29 rows selected. The blue line represents the space occupied by the synopsis for global level statistics. Usually, it will only consume very little space. Using sql_trace, found that the attribute for incremental for a table is stored in table SYS.OPTSTAT_USER_PREF$: SQL> select a.obj#, name, pname, valchar from SYS.OPTSTAT_USER_PREFS$ a, obj$ b where a.obj# = b.obj#; OBJ# NAME PNAME VALCHAR ---------- ------------------------------ -------------------- ---------------- 15307 TEST_INC INCREMENTAL TRUE In fact, for a partitioned table, the global level “NDV” (Number of Distinct Value) of NDV” columns is the most challengeable. All other statistics can be speculated from partition level, such as num_rows, blocks, avg_row_len. So, I think, this is what Oracle 11G Release 2 enhances. 4. My conclusion: I think, incremental statistics gathering for partitioned tables is a very useful new feature introduced by ORACLE 11G if all the bugs can be resolved. It will consume much less resource especially for large partitioned/subpartitioned tables and shorten our statistics gathering process. I believe it will not only help us for our normal analyze CR, but also it will help us under situations under tough situations (such as TCB) caused by inaccurate statistics, as at such situations, time is so precious for us. Anyway, I will track this feature. Thanks!