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
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
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!