You are on page 1of 24

_s-xclick

FRH3Y5SVPL2W

DBA Tips Archive for Oracle

Gather Statistics with DBMS_STATS


by Jeff Hunter, Sr. Database Administrator
Contents
1. Overview
2. Missing statistics
3. Analyze vs. DBMS_STATS
4. What gets collected?
5. Where are the statistics stored?
6. Compute statistics vs. Estimate statistics
7. DBMS_STATS functions and variable definitions
8. DBMS_STATS in action (Examples)
9. Automated table monitoring and stale statistics gathering example
10. How to determine if dictionary statistics are RDBMS-generated or user-defined
Overview
Oracle's cost-based optimizer (COB) uses statistics to calculate the selectivity (the fraction of
rows in a table that the SQL statement's predicate chooses) of predicates and to estimate the
"cost" of each execution plan. The COB will use the selectivity of a predicate to estimate the cost
of a particular access method and to determin the optimal join order.

GE Internal

Statistics are used to quantify the data distribution and storage characteristics of tables, columns,
indexes and partitions. The COB uses these statistics to estimate how much I/O and memory are
required to execute a SQL statement using a particular execution plan. Statistics are stored in the
data dictionary, and they can be exported from one database and imported into another.
Situations in where you would want to perform this, might be to transfer production statistics to a
test system to simulate the real environment, even though the test system may only have small
samples of the data.
In order to give the Oracle cost-based optimizer the most up-to-date information about schema
objects (and the best chance for choosing a good execution plan) all application tables and
indexes to be accessed must be analyzed. New statistics should be gathered on schema objects
that are out of date. After loading or deleting large amounts of data would obviously change the
number of rows. Other changes like updating a large amount of rows would not effect the
number of rows, but may effect the average row length.
Statistics can be generated with the ANALYZE statement or with the package DBMS_STATS
(introduced in Oracle8i). The DBMS_STATS package is great for DBA's in managing database
statistics only for use by the COB. The package itself allows the DBA to create, modify, view
and delete statistics from a standard, well-defined set of package procedures. The statistics can
be gathered on tables, indexes, columns, partitions and schemas, but note that it does not
generate statistics for clusters.
provides a mechanism for you to view and modify optimizer statistics gathered for
database objects.The statistics can reside in two different locations:
DBMS_STATS

The dictionary.

A table created in the user's schema for this purpose.

Only statistics stored in the dictionary itself have an impact on the cost-based optimizer.
When you generate statistics for a table, column, or index, if the data dictionary already contains
statistics for the object, then Oracle updates the existing statistics. Oracle also invalidates any
currently parsed SQL statements that access the object.
The next time such a statement executes, the optimizer automatically chooses a new execution
plan based on the new statistics. Distributed statements issued on remote databases that access
the analyzed objects use the new statistics the next time Oracle parses them.
When you associate a statistics type with a column or domain index, Oracle calls the statistics
collection method in the statistics type if you analyze the column or domain index.
Missing statistics
When statistics do not exist on schema objects, the optimizer uses the following default values.

GE Internal

Tables
Statistic

Default Value Used by Optimizer

Cardinality

100 rows

Avg. row len

20 bytes

No. of blocks

100

Remote cardinality

2000 rows

Remote average row length

100 bytes
Indexes

Statistic

Default Value Used by Optimizer

Levels

Leaf blocks

25

Leaf blocks/key

Data blocks/key

Distinct keys

100

Clustering factor

800 (8*no. of blocks)

Analyze vs. DBMS_STATS


The following is a quick overview of the two.

Analyze
o The only method available for collecting statistics in Oracle 8.0 and lower.
o ANALYZE can only run serially.
o ANALYZE cannot overwrite or delete certain types of statistics that where
generated by DBMS_STATS.
o ANALYZE calculates global statistics for partitioned tables and indexes
instead of gathering them directly. This can lead to inaccuracies for some
statistics, such as the number of distinct values.

For partitioned tables and indexes, ANALYZE gathers statistics for


the individual partitions and then calculates the global statistics
from the partition statistics.

For composite partitioning, ANALYZE gathers statistics for the


subpartitions and then calculates the partition statistics and global
statistics from the subpartition statistics.

GE Internal

o ANALYZE can gather additional information that is not used by the


optimizer, such as information about chained rows and the structural
integrity of indexes, tables, and clusters. DBMS_STATS does not gather this
information.
o No easy way of knowing which tables or how much data within the tables
have changed. The DBA would generally re-analyze all of their tables on a
semi-regular basis.

DBMS_STATS
o Only available for Oracle 8i and higher.
o Statistics can be generated to a statistics table and can then be imported or
exported between databases and re-loaded into the data dictionary at any
time. This allows the DBA to experiment with various statistics.
o DBMS_STATS routines have the option to run via parallel query or operate
serially.
o Can gather statistics for sub-partitions or partitions.
o Certain DDL commands (ie. create index) automatically generate
statistics, therefore eliminating the need to generate statistics explicitly
after DDL command.
o DBMS_STATS does not generate information about chained rows and the
structural integrity of segments.
o The DBA can set a particular table, a whole schema or the entire database
to be automatically monitored when a modification occurs. When enabled,
any change (insert, update, delete, direct load, truncate, etc.) that occurs on
a table will be tracked in the SGA. This information is incorporated into
the data dictionary by the SMON process at a pre-set interval (every 3
hours in Oracle 8.1.x, and every 15 minutes in Oracle 9i). The information
collected by this monitoring can be seen in the DBA_TAB_MODIFICATIONS
view. Oracle 9i introduced a new function in the DBMS_STATS package
called: FLUSH_DATABASE_MONITORING_INFO. The DBA can make use of
this function to flush the monitored table data more frequently. Oracle 9i
will also automatically call this procedure prior to executing DBMS_STATS
for statistics gathering purposes. Note that this function is not included
with Oracle 8i.
o DBMS_STATS provides a more efficient, scalable solution for statistics
gathering and should be used over the traditional ANALYZE command

GE Internal

which does not support features such as parallelism and stale statistics
collection.
o Use of table monitoring in conjunction with DBMS_STATS stale object
statistics generation is highly recommended for environments with large,
random and/or sporadic data changes. These features allow the database to
more efficiently determine which tables should be re-analyzed versus the
DBA having to force statistics collection for all tables. Including those
that have not changed enough to merit a re-scan)
What gets collected?
Table Statistics
Oracle collects the following statistics for a table. Statistics marked with an asterisk are always
computed exactly. Table statistics, including the status of domain indexes, appear in the data
dictionary views USER_TABLES, ALL_TABLES, and DBA_TABLES in the columns shown in
parentheses.

Number of rows (NUM_ROWS)

* Number of data blocks below the high water mark (that is, the number of
data blocks that have been formatted to receive data, regardless whether
they currently contain data or are empty) (BLOCKS)

* Number of data blocks allocated to the table that have never been used
(EMPTY_BLOCKS)

Average available free space in each data block in bytes (AVG_SPACE)

Number of chained rows. [Not collected by DBMS_STATS]


(CHAIN_COUNT)

Average row length, including the row's overhead, in bytes


(AVG_ROW_LEN)

Index Statistics
Oracle collects the following statistics for an index. Statistics marked with an asterisk are always
computed exactly. For conventional indexes, the statistics appear in the data dictionary views
USER_INDEXES, ALL_INDEXES, and DBA_INDEXES in the columns in parentheses.

* Depth of the index from its root block to its leaf blocks (BLEVEL)

Number of leaf blocks (LEAF_BLOCKS)

GE Internal

Number of distinct index values (DISTINCT_KEYS)

Average number of leaf blocks per index value


(AVG_LEAF_BLOCKS_PER_KEY)

Average number of data blocks per index value (for an index on a table)
(AVG_DATA_BLOCKS_PER_KEY)

Clustering factor (how well ordered the rows are about the indexed values)
(CLUSTERING_FACTOR)

Where are the statistics stored?


Statistics are stored into the Oracle Data Dictionary, in tables owned by SYS. Views are created
on these tables to retrieve data more easily.
These views are prefixed with DBA_ or ALL_ or USER_. For ease of reading, we will use DBA_%
views, but ALL_% views or USER_% views could be used as well.
Conventions Used
-

Statistics
Statistics
Statistics
Statistics

available only since 8.0.X rdbms release


:
available only since 8.1.X rdbms release
:
not available at partition or subpartition level :
not available at subpartition level
:

(*)
(**)
(G)
(GP)

Table level statistics can be retrieved from:

DBA_ALL_TABLES - (8.X onwards)


DBA_OBJECT_TABLES - (8.X onwards
DBA_TABLES - (all versions)
DBA_TAB_PARTITIONS - (8.X onwards)
DBA_TAB_SUBPARTITIONS - (8.1 onwards)

Columns to look at are:


NUM_ROWS
computed
BLOCKS
even
statements
EMPTY_BLOCKS
AVG_SPACE
blocks

: Number of rows (always exact even when


with ESTIMATE method)
: Number of blocks which have been used
if they are empty due to delete
: Number of empty blocks (these blocks have
never been used)
: Average amount of FREE space in bytes in
allocated to the table : Blocks + Empty

Blocks

GE Internal

CHAIN_CNT
AVG_ROW_LEN
AVG_SPACE_FREELIST_BLOCKS (*)(G)
freelist
NUM_FREELIST_BLOCKS
(*)(G)
SAMPLE_SIZE
COMPUTE)
LAST_ANALYZED
GLOBAL_STATS
(**)
statistics

: Number of chained or migrated rows


: Average length of rows in bytes
: Average free space of blocks in the
: Number of blocks in the freelist
: Sample defined in ESTIMATE method (0 if
: Timestamp of last analysis
: For partitioned tables, YES means
are collected for the TABLE as a whole
NO means statistics are estimated from

statistics
subpartitions
USER_STATS
user

on underlying table partitions or


(**)

: YES if statistics entered directly by the

Index level statistics can be retrieved from:


DBA_INDEXES - (all versions )
DBA_IND_PARTITIONS - (8.X onwards)
DBA_IND_SUBPARTITIONS - (8.1 onwards )
Columns to look at are:
BLEVEL
root
LEAF_BLOCKS
DISTINCT_KEYS
AVG_LEAF_BLOCKS_PER_KEY
AVG_DATA_BLOCKS_PER_KEY
that
CLUSTERING_FACTOR
table is
block

single
SAMPLE_SIZE
COMPUTE)
LAST_ANALYZED
GLOBAL_STATS
statistics
subpartitions

: B*Tree level : depth of the index from its


block to its leaf blocks
: Number of leaf blocks
: Number of distinct keys
: Average number of leaf blocks in which each
distinct key appears (1 for a UNIQUE index)
: Average number of data blocks in the table
are pointed to by a distinct key
: - if near the number of blocks, then the
ordered : index entries in a single leaf
tend to point to rows in same data block
- if near the number of rows, the table is
randomly ordered : index entries in a
leaf block are unlikely to point to rows in
same data block
: Sample defined in ESTIMATE method (0 if
: Timestamp of last analysis
(**) : For partitioned indexes, YES means statistics
are collected for the INDEX as a whole
NO means statistics are estimated from
on underlying index partitions or

GE Internal

USER_STATS
user
PCT_DIRECT_ACCESS

(**) : YES if statistics entered directly by the


(**)(GP) : For secondary indexes on IOTs, percentage of
rows with VALID guess

Column level statistics can be retrieved from:

DBA_TAB_COLUMNS - (all versions)


DBA_TAB_COL_STATISTICS - (Version 8.X onwards)
DBA_PART_COL_STATISTICS - (Version 8.X onwards)
DBA_SUBPART_COL_STATISTICS - (Version 8.1 onwards)

The last three views extract statistics data from DBA_TAB_COLUMNS.


Columns to look at are:
NUM_DISTINCT
LOW_VALUE
LOW_VALUE
DENSITY
NUM_NULLS
AVG_COL_LEN
NUM_BUCKETS
SAMPLE_SIZE
COMPUTE)
LAST_ANALYZED
(**)GLOBAL_STATS
statistics
subpartitions
(**)USER_STATS
user

:
:
:
:
:
:
:
:

Number of distinct values


Lowest value
Highest value
Density
Number of columns having a NULL value
Average length in bytes
Number of buckets in histogram for the column
Sample defined in ESTIMATE method (0 if

: Timestamp of last analysis


: For partitioned tables, YES means statistics
are collected for the TABLE as a whole
NO means statistics are estimated from
on underlying table partitions or
: YES if statistics entered directly by the

Compute statistics vs. Estimate statistics


Both computed and estimated statistics are used by the Oracle optimizer to choose the execution
plan for SQL statements that access analyzed objects. These statistics may also be useful to
application developers who write such statements.
COMPUTE STATISTICS
instructs Oracle to compute exact statistics about the analyzed object and
store them in the data dictionary.
COMPUTE STATISTICS

When computing statistics, an entire object is scanned to gather data about the object. This data
is used by Oracle to compute exact statistics about the object. Slight variances throughout the
object are accounted for in these computed statistics. Because an entire object is scanned to

GE Internal

gather information for computed statistics, the larger the size of an object, the more work that is
required to gather the necessary information.
To perform an exact computation, Oracle requires enough space to perform a scan and sort of the
table. If there is not enough space in memory, then temporary space may be required. For
estimations, Oracle requires enough space to perform a scan and sort of only the rows in the
requested sample of the table. For indexes, computation does not take up as much time or space,
so it is best to perform a full computation.
Some statistics are always computed exactly, such as the number of data blocks currently
containing data in a table or the depth of an index from its root block to its leaf blocks.
Use estimation for tables and clusters rather than computation, unless you need exact values.
Because estimation rarely sorts, it is often much faster than computation, especially for large
tables.
ESTIMATE STATISTICS
instructs Oracle to estimate statistics about the analyzed object and
stores them in the data dictionary.
ESTIMATE STATISTICS

When estimating statistics, Oracle gathers representative information from portions of an object.
This subset of information provides reasonable, estimated statistics about the object. The
accuracy of estimated statistics depends upon how representative the sampling used by Oracle is.
Only parts of an object are scanned to gather information for estimated statistics, so an object can
be analyzed quickly. You can optionally specify the number or percentage of rows that Oracle
should use in making the estimate.
To estimate statistics, Oracle selects a random sample of data. You can specify the sampling
percentage and whether sampling should be based on rows or blocks.

Row sampling reads rows without regard to their physical placement on


disk. This provides the most random data for estimates, but it can result in
reading more data than necessary. For example, in the worst case a row
sample might select one row from each block, requiring a full scan of the
table or index.

Block sampling reads a random sample of blocks and uses all of the rows
in those blocks for estimates. This reduces the amount of I/O activity for a
given sample size, but it can reduce the randomness of the sample if rows
are not randomly distributed on disk. Block sampling is not available for
index statistics.

Notes on estimating statistics

GE Internal

The default estimate of the analyze command reads the first approx 1064
rows of the table so the results often leave a lot to be desired.

The general consensus is that the default value of 1064 is not sufficient for
accurate statistics when dealing with tables of any size. Many claims have
shown that estimating statistics on 30 percent produces very accurate
results. I personally have been running estimate 35 percent. This seems to
produce very accurate numbers. It also saves a lot of time over full scans.

Note that if an estimate does 50% or more of a table Oracle converts the
estimate to a full compute statistics.

DBMS_STATS functions and variable definitions


Most of the DBMS_STATS procedures include the three parameters statown, stattab, and
statid. These parameters allow you to store statistics in your own tables (outside of the
dictionary), which does not affect the optimizer. Therefore, you can maintain and experiment
with sets of statistics.
The stattab parameter specifies the name of a table in which to hold statistics, and it is assumed
that it resides in the same schema as the object for which statistics are collected (unless the
statown parameter is specified). Users may create multiple tables with different stattab
identifiers to hold separate sets of statistics.
Additionally, users can maintain different sets of statistics within a single stattab by using the
statid parameter, which can help avoid cluttering the user's schema.
For all of the SET or GET procedures, if stattab is not provided (i.e., NULL), then the
operation works directly on the dictionary statistics; therefore, users do not need to create these
statistics tables if they only plan to modify the dictionary directly. However, if stattab is not
NULL, then the SET or GET operation works on the specified user statistics table, and not the
dictionary.
Create Stats Table
DBMS_STATS.CREATE_STAT_TABLE (
ownname VARCHAR2,
stattab VARCHAR2,
tblspace VARCHAR2 DEFAULT NULL);

ownname : Name of the schema.

stattab : Name of the table to create. This value should be passed as the stattab
parameter to other procedures when the user does not want to modify the
dictionary statistics directly.

GE Internal

tblspace : Tablespace in which to create the stat tables. If none is specified, then
they are created in the user's default tablespace.

Drop Stats Table


DBMS_STATS.drop_stat_table (
ownname VARCHAR2,
stattab VARCHAR2);

ownname : Name of the schema.

stattab : User stat table identifier.

Gather Schema Stats


DBMS_STATS.gather_schema_stats (
ownname
VARCHAR2,
estimate_percent NUMBER
DEFAULT
block_sample
BOOLEAN DEFAULT
method_opt
VARCHAR2 DEFAULT
degree
NUMBER
DEFAULT
granularity
VARCHAR2 DEFAULT
cascade
BOOLEAN DEFAULT
stattab
VARCHAR2 DEFAULT
statid
VARCHAR2 DEFAULT
options
VARCHAR2 DEFAULT
objlist
OUT ObjectTab,
statown
VARCHAR2 DEFAULT

NULL,
FALSE,
'FOR ALL COLUMNS SIZE 1',
NULL,
'DEFAULT',
FALSE,
NULL,
NULL,
'GATHER',
NULL);

ownname : Schema to analyze (NULL means current schema).

estimate_percent : Percentage of rows to estimate (NULL means compute): The


valid range is [0.000001,100).

block_sample : Whether or not to use random block sampling instead of random


row sampling. Random block sampling is more efficient, but if the data is not
randomly distributed on disk, then the sample values may be somewhat
correlated. Only pertinent when doing an estimate statistics.

method_opt : Method options of the following format (the phrase 'SIZE 1' is
required to ensure gathering statistics in parallel and for use with the phrase
hidden):
FOR ALL [INDEXED | HIDDEN] COLUMNS [SIZE integer]

This value is passed to all of the individual tables.

degree : Degree of parallelism (NULL means use table default value).

GE Internal

granularity : Granularity of statistics to collect (only pertinent if the table is


partitioned).
o DEFAULT: Gather global- and partition-level statistics.
o SUBPARTITION: Gather subpartition-level statistics.
o PARTITION: Gather partition-level statistics.
o GLOBAL: Gather global statistics.
o ALL: Gather all (subpartition, partition, and global) statistics.

cascade : Gather statistics on the indexes as well.


Index statistics gathering is not parallelized. Using this option is equivalent to
running the gather_index_stats procedure on each of the indexes in the schema in
addition to gathering table and column statistics.

stattab : User stat table identifier describing where to save the current statistics.

statid : Identifier (optional) to associate with these statistics within stattab.

options : Further specification of which objects to gather statistics for:


o GATHER: Gather statistics on all objects in the schema.
o GATHER STALE: Gather statistics on stale objects as determined by
looking at the *_tab_modifications views. Also, return a list of objects
found to be stale.
o GATHER EMPTY: Gather statistics on objects which currently have no
statistics. also, return a list of objects found to have no statistics.
o LIST STALE: Return list of stale objects as determined by looking at the
*_tab_modifications views.
o LIST EMPTY: Return list of objects which currently have no statistics.

objlist : List of objects found to be stale or empty.

statown : Schema containing stattab (if different than ownname).

Export Schema Stats

GE Internal

DBMS_STATS.export_schema_stats (
ownname VARCHAR2,
stattab VARCHAR2,
statid VARCHAR2 DEFAULT NULL,
statown VARCHAR2 DEFAULT NULL);

ownname : Name of the schema.

stattab : User stat table identifier describing where to store the statistics.

statid : Identifier (optional) to associate with these statistics within stattab.

statown : Schema containing stattab (if different than ownname).

Import Schema Stats


DBMS_STATS.import_schema_stats (
ownname VARCHAR2,
stattab VARCHAR2,
statid VARCHAR2 DEFAULT NULL,
statown VARCHAR2 DEFAULT NULL);

ownname : Name of the schema.

stattab : User stat table identifier describing from where to retrieve the statistics.

statid : Identifier (optional) to associate with these statistics within stattab.

statown : Schema containing stattab (if different than ownname).

Delete Schema Stats


DBMS_STATS.delete_schema_stats (
ownname VARCHAR2,
stattab VARCHAR2 DEFAULT NULL,
statid VARCHAR2 DEFAULT NULL,
statown VARCHAR2 DEFAULT NULL);

ownname : Name of the schema.

stattab : User stat table identifier describing from where to delete the statistics. If
stattab is NULL, then the statistics are deleted directly in the dictionary.

statid : Identifier (optional) to associate with these statistics within stattab (Only
pertinent if stattab is not NULL).

statown : Schema containing stattab (if different than ownname).

GE Internal

Set Table Stats


DBMS_STATS.set_table_stats (
ownname VARCHAR2,
tabname VARCHAR2,
partname VARCHAR2 DEFAULT NULL,
stattab VARCHAR2 DEFAULT NULL,
statid
VARCHAR2 DEFAULT NULL,
numrows NUMBER
DEFAULT NULL,
numblks NUMBER
DEFAULT NULL,
avgrlen NUMBER
DEFAULT NULL,
flags
NUMBER
DEFAULT NULL,
statown VARCHAR2 DEFAULT NULL);

ownname : Name of the schema.

tabname : Name of the table.

partname : Name of the table partition in which to store the statistics. If the table
is partitioned and partname is NULL, then the statistics are stored at the global
table level.

stattab : User stat table identifier describing where to store the statistics. If stattab
is NULL, then the statistics are stored directly in the dictionary.

statid : Identifier (optional) to associate with these statistics within stattab (Only
pertinent if stattab is not NULL).

numrows : Number of rows in the table (partition).

numblks : Number of blocks the table (partition) occupies.

avgrlen : Average row length for the table (partition).

flags : For internal Oracle use (should be left as NULL).

statown : Schema containing stattab (if different than ownname).

Get Table Stats


DBMS_STATS.get_table_stats (
ownname
VARCHAR2,
tabname
VARCHAR2,
partname
VARCHAR2 DEFAULT NULL,
stattab
VARCHAR2 DEFAULT NULL,
statid
VARCHAR2 DEFAULT NULL,
numrows OUT NUMBER,
numblks OUT NUMBER,

GE Internal

avgrlen OUT NUMBER,


statown
VARCHAR2 DEFAULT NULL);

ownname : Name of the schema.

tabname : Name of the table to which this column belongs.

partname : Name of the table partition from which to get the statistics. If the
table is partitioned and if partname is NULL, then the statistics are retrieved from
the global table level.

stattab : User stat table identifier describing from where to retrieve the statistics.
If stattab is NULL, then the statistics are retrieved directly from the dictionary.

statid : Identifier (optional) to associate with these statistics within stattab (Only
pertinent if stattab is not NULL).

numrows : Number of rows in the table (partition).

numblks : Number of blocks the table (partition) occupies.

avgrlen : Average row length for the table (partition).

statown : Schema containing stattab (if different than ownname).

Get Index Stats


DBMS_STATS.GET_INDEX_STATS (
ownname
VARCHAR2,
indname
VARCHAR2,
partname
VARCHAR2 DEFAULT
stattab
VARCHAR2 DEFAULT
statid
VARCHAR2 DEFAULT
numrows OUT NUMBER,
numlblks OUT NUMBER,
numdist OUT NUMBER,
avglblk OUT NUMBER,
avgdblk OUT NUMBER,
clstfct OUT NUMBER,
indlevel OUT NUMBER,
statown
VARCHAR2 DEFAULT

NULL,
NULL,
NULL,

NULL);

ownname : Name of the schema.

indname : Name of the index.

GE Internal

partname : Name of the index partition for which to get the statistics. If the index
is partitioned and if partname is NULL, then the statistics are retrieved for the
global index level.

stattab : User stat table identifier describing from where to retrieve the statistics.
If stattab is NULL, then the statistics are retrieved directly from the dictionary.

statid : Identifier (optional) to associate with these statistics within stattab (Only
pertinent if stattab is not NULL).

numrows : Number of rows in the index (partition).

numlblks : Number of leaf blocks in the index (partition).

numdist : Number of distinct keys in the index (partition).

avglblk : Average integral number of leaf blocks in which each distinct key
appears for this index (partition).

avgdblk : Average integral number of data blocks in the table pointed to by a


distinct key for this index (partition).

clstfct : Clustering factor for the index (partition).

indlevel : Height of the index (partition).

statown : Schema containing stattab (if different than ownname).

DBMS_STATS in action (Examples)


Create Stats Table
BEGIN
DBMS_STATS.create_stat_table (
ownname => 'scott',
stattab => 'stats_table',
tblspace => 'users');
END;
/

Drop Stats Table


BEGIN
DBMS_STATS.drop_stat_table (
ownname => 'scott',
stattab => 'stats_table');
END;
/

Gather Schema Stats to Data Dictionary

GE Internal

BEGIN
DBMS_STATS.gather_schema_stats (
ownname
=> 'scott',
estimate_percent => null,
block_sample
=> false,
method_opt
=> 'FOR ALL COLUMNS SIZE 1',
degree
=> null,
granularity
=> 'ALL',
cascade
=> true,
options
=> 'GATHER');
END;
/

Gather Schema Stats to Stats Table


BEGIN
DBMS_STATS.gather_schema_stats (
ownname
=> 'scott',
estimate_percent => null,
block_sample
=> false,
method_opt
=> 'FOR ALL COLUMNS SIZE 1',
degree
=> null,
granularity
=> 'ALL',
cascade
=> true,
stattab
=> 'stats_table',
statid
=> 'TEST1',
options
=> 'GATHER',
statown
=> 'scott');
END;
/

Export Schema Statistics from Data Dictionary to Stats Table


BEGIN
DBMS_STATS.export_schema_stats (
ownname => 'scott',
stattab => 'stats_table_backup',
statid
=> 'BACKUP_TEST1',
statown => 'scott');
END;
/

Import Schema Statistics from Data Dictionary to Stats Table


BEGIN
DBMS_STATS.import_schema_stats (
ownname => 'scott',
stattab => 'stats_table',
statid
=> 'TEST1',
statown => 'scott');
END;
/

Delete Schema Stats from Data Dictionary

BEGIN
DBMS_STATS.delete_schema_stats ('scott');
END;
/

Delete Schema Stats from Stats Table

BEGIN
DBMS_STATS.delete_schema_stats (
ownname => 'scott',
stattab => 'stats_table_backup',
GE Internal

statid
statown

=> 'BACKUP_TEST1',
=> 'scott');

END;
/

Set Table Stats (Manually) in the Data Dictionary


BEGIN
DBMS_STATS.set_table_stats (
ownname => 'scott',
tabname => 'emp',
partname => null,
numrows => 650000000,
numblks => 53455443,
avgrlen => 212,
flags
=> null);
END;
/

Set Table Stats (Manually) in the Stats Table


BEGIN
DBMS_STATS.set_table_stats (
ownname => 'scott',
tabname => 'emp',
partname => null,
stattab => 'stats_table',
statid
=> 'TEST1',
numrows => 650000000,
numblks => 53455443,
avgrlen => 212,
flags
=> null,
statown => 'scott');
END;
/

Get Table Statistics in SQL*Plus Variables


SQL> variable NUMROWS number
SQL> variable NUMBLKS number
SQL> variable AVGRLEN number

BEGIN
DBMS_STATS.get_table_stats (
'scott',
'emp',
NUMROWS=>:numrows,
NUMBLKS=>:numblks,
AVGRLEN=>:avgrlen);
END;
/
PL/SQL procedure successfully completed.
SQL> print NUMROWS NUMBLKS AVGRLEN
NUMROWS
---------1000
NUMBLKS
----------

GE Internal

28
AVGRLEN
---------92

Get Index Statistics in SQL*Plus Variables


SQL>
SQL>
SQL>
SQL>
SQL>
SQL>
SQL>

variable
variable
variable
variable
variable
variable
variable

NUMROWS number
NUMLBLKS number
NUMDIST number
AVGLBLK number
AVGDBLK number
CLSTFCT number
INDLEVEL number

BEGIN
DBMS_STATS.get_index_stats (
'SCOTT',
'EMP_PK',
NUMROWS
=> :NUMROWS,
NUMLBLKS => :NUMLBLKS,
NUMDIST
=> :NUMDIST,
AVGLBLK
=> :AVGLBLK,
AVGDBLK
=> :AVGDBLK,
CLSTFCT
=> :CLSTFCT,
INDLEVEL => :INDLEVEL);
END;
/
PL/SQL procedure successfully completed.
SQL> print NUMROWS NUMLBLKS NUMDIST AVGLBLK AVGDBLK CLSTFCT INDLEVEL
NUMROWS
---------1000
NUMLBLKS
---------3
NUMDIST
---------1000
AVGLBLK
---------1
AVGDBLK
---------1
CLSTFCT
---------15

GE Internal

INDLEVEL
---------1

Automated table monitoring and stale statistics gathering example


You can automatically gather statistics or create lists of tables that have stale or no statistics.
To automatically gather statistics, run the DBMS_STATS.GATHER_SCHEMA_STATS and
DBMS_STATS.GATHER_DATABASE_STATS procedures with the OPTIONS and objlist
parameters. Use the following values for the options parameter:

GATHER STALE : Gathers statistics on tables with stale statistics.

GATHER : Gathers statistics on all tables. (default)

GATHER EMPTY : Gathers statistics only on tables without statistics.

LIST STALE : Creates a list of tables with stale statistics.

LIST EMPTY : Creates a list of tables that do not have statistics.

The objlist parameter identifies an output parameter for the LIST STALE and LIST EMPTY
options. The objlist parameter is of type DBMS_STATS.OBJECTTAB.
Step 1 : Perform a quick analyze to load in base statistics
BEGIN
DBMS_STATS.GATHER_SCHEMA_STATS (
ownname
=> 'scott',
estimate_percent => null,
block_sample
=> false,
method_opt
=> 'FOR ALL COLUMNS',
degree
=> null,
example
granularity
=> 'ALL',
cascade
=> true,
options
=> 'GATHER'
);
END;
/

-- Small table, lets compute


-- No parallelism used in this
-- Make sure we include indexes
-- Gather mode

PL/SQL procedure successfully completed.

Step 2 : Examine the current statistics


SELECT table_name, num_rows, blocks, avg_row_len
FROM user_tables
WHERE table_name='EMP';

GE Internal

TABLE_NAME
NUM_ROWS
BLOCKS AVG_ROW_LEN
------------------------------ ---------- ---------- ----------EMP
1500
28
92

Step 3 : Turn on Automatic Monitoring


Now turn on automatic monitoring for the emp table. This can be done using the alter table
method. Starting with Oracle 9i, you can also perform this at the "schema", and "entire database"
level. I provide the syntax for all three methods below.
Monitor only the EMP table.
alter table emp monitoring;
Table altered.

Monitor all of the tables within Scott's schema. (Oracle 9i and higher)
BEGIN
DBMS_STATS.alter_schema_tab_monitoring('scott', true);
END;
/
PL/SQL procedure successfully completed.

Monitor all of the tables within the database. (Oracle 9i and higher)
Note: Although the option to collect statistics for SYS tables is available via
ALTER_DATABASE_TAB_MONITORING, Oracle continues to recommend against this practice
until the next major release after 9i Release 2. Also note that the
ALTER_DATABASE_TAB_MONITORING procedure in the DBMS_STATS package only
monitors tables; there is an ALTER INDEX...MONITORING statement which can be used to
monitor indexes. Thanks to Nabil Nawaz for providing this and pointing out an error I made in
the previous version of this article.
BEGIN
DBMS_STATS.alter_database_tab_monitoring (
monitoring => true,
sysobjs
=> false);
-- Don't set to true, see note above.
END;
/
PL/SQL procedure successfully completed.

Step 4 : Verify that monitoring is turned on.


Note: The results of the following query are from running the alter table ... statement on
the emp table only.
SELECT table_name, monitoring
FROM user_tables
ORDER BY monitoring;
TABLE_NAME
MONITORING
------------------------------ ----------

GE Internal

DEPT
EMP

NO
YES

Step 5 : Delete some rows from the database.


SQL> DELETE FROM emp WHERE rownum < 501;
500 rows deleted.
SQL> commit;
Commit complete.

Step 6 : Wait until the monitered data is flushed.


Data can be flushed in several ways.

In Oracle 8i, you can wait it out for 3 hours.

In Oracle 9i and higher, you only need to wait 15 minutes.

In either version, restart the database.

For immediate results in Oracle 9i and higher, use the


DBMS_STATS.flush_database_monitoring_info package.

OK, I'm impatient...

exec dbms_stats.flush_database_monitoring_info;
PL/SQL procedure successfully completed.

Step 7 : Check for what it has collected.


As user "scott", check USER_TAB_MODIFICATIONS to see what it was collected.
SELECT * FROM user_tab_modifications;
TABLE_NAME PARTITION_NAME SUBPARTITION_NAME INSERTS UPDATES DELETES TIMESTAMP
TRUNCATED
---------- -------------- ----------------- ------- ------- ------- ----------------EMP
0
0
500 18-SEP-02
NO

Step 8 : Execute DBMS_STATS to gather stats on all "stale" tables.


BEGIN
DBMS_STATS.GATHER_SCHEMA_STATS(
ownname
=> 'scott',
estimate_percent => null,
block_sample
=> false,

GE Internal

method_opt
degree
granularity
cascade
options

END;
/

=>
=>
=>
=>
=>

'FOR ALL COLUMNS',


null,
'ALL',
true,
'GATHER STALE');

PL/SQL procedure successfully completed.

Step 9 : Verify that the table is no longer listed in USER_TAB_MODIFICATIONS.


SQL> SELECT * FROM user_tab_modifications;
no rows selected.

Step 10 : Examine some of new statistics collected.


SELECT table_name, num_rows, blocks, avg_row_len
FROM user_tables where table_name='EMP';
TABLE_NAME
NUM_ROWS
BLOCKS AVG_ROW_LEN
------------------------------ ---------- ---------- ----------EMP
1000
28
92

How to determine if dictionary statistics are RDBMS-generated or user-defined


The following section explains how to determine if your dictionary statistics are RDBMSgenerated or set by users through one of the DBMS_STATS.SET_xx_STATS procedures.
This is crucial for development environments that are testing the performance of SQL statements
with various sets of statistics. The DBA will need to know if the relying statistics are RDBMSdefined or user-defined.
RDBMS-generated statistics are generated by the following:

ANALYZE SQL command

DBMS_UTILITY.ANALYZE_SCHEMA procedure

DBMS_UTILITY.ANALYZE_DATABASE procedure

DBMS_DDL.ANALYZE_OBJECT procedure

8.1 DBMS_STATS.GATHER_xx_STATS procedures

User generated statistics are only done through the use of the DBMS_STATS.SET_xx_STATS
procedures

GE Internal

The column USER_STATS from DBA_TABLES, ALL_TABLES, USER_TABLES displays:

YES, when statistics are entered directly by a user.

NO, when statistics are generated by RDBMS through an ANALYZE statement.

GE Internal

You might also like