How to gathering Database Statistics in Oracle

When a valid SQL statement is sent to the server for the first time, Oracle produces an execution plan that describes how to retrieve the necessary data. In older versions of the database this execution plan could be generated using one of two optimizers:

  • Rule-Based Optimizer (RBO) - This was the original optimization method and as the name suggests, was essentially a list of rules Oracle should follow to generate an execution plan. Even after the cost-based optimizer was introduced, this method was used if the server had no internal statistics relating to the objects referenced by the statement, or if explicitly requested by a hint or instance/session parameter. This optimizer was made obsolete, then deprecated in later versions of the database.
  • Cost-Based Optimizer (CBO) - The CBO uses database statistics to generate several execution plans, picking the one with the lowest cost, where cost relates to system resources required to complete the operation

what should our statistics strategy be? Here are some suggestions.

  • Automatic Optimizer Statistics Collection: From 10g onward the database automatically gathers statistics on a daily basis. The default statistics job has come under a lot of criticism over the years, but its value depends on the type of systems you are managing. Most of that criticism has come from people discussing edge cases, like large data warehouses. If you are managing lots of small databases that have relatively modest performance requirements, you can pretty much let Oracle do its own thing where stats are concerned. If you have any specific problems, deal with them on a case by case basis.
  • Mixed Approach: You rely on the automatic job for the majority of stats collection, but you have specific tables or schemas that have very specific stats requirements. In these cases you can either set the preferences for the objects in question, or lock the stats for the specific tables/schemas to prevent the job from changing them, then devise a custom solution for those tables/schemas.
  • Manual: You disable the automatic stats collection completely and devise a custom solution for the whole of the database.

Which one of these approaches you take should be decided on a case-by-case basis. Whichever route you take, you will be using the DBMS_STATS package to manage your stats.

Regardless of the approach you take, you need to consider system and fixed object statistics for every database, as these are not gathered by the automatic job.

DBMS_STATS

The DBMS_STATS package was introduced in Oracle 8i and is Oracle's preferred method of gathering statistics. Oracle list a number of benefits to using it including parallel execution, long term storage of statistics and transfer of statistics between servers.

Table and Index Stats

Table statistics can be gathered for the database, schema, table or partition.

[oracle@oracle-db-19c ~]$ sqlplus / as sysdba

SQL*Plus: Release 19.0.0.0.0 - Production on Thu Feb 16 08:52:54 2023
Version 19.3.0.0.0

Copyright (c) 1982, 2019, Oracle.  All rights reserved.


Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0

SQL> show user;
USER is "SYS"
SQL> show con_name;

CON_NAME
------------------------------
CDB$ROOT
SQL> 
SQL> ALTER SESSION SET CONTAINER=PDB1;

Session altered.

SQL> show user;
USER is "SYS"
SQL> show con_name;

CON_NAME
------------------------------
PDB1
SQL> EXEC DBMS_STATS.gather_database_stats;

PL/SQL procedure successfully completed.

SQL> 
SQL> EXEC DBMS_STATS.gather_database_stats(estimate_percent => 15);

PL/SQL procedure successfully completed.

SQL> EXEC DBMS_STATS.gather_database_stats(estimate_percent => 15, cascade => TRUE);

PL/SQL procedure successfully completed.

SQL> 

SQL> EXEC DBMS_STATS.gather_schema_stats('SCOTT');

PL/SQL procedure successfully completed.

SQL> EXEC DBMS_STATS.gather_schema_stats('SCOTT', estimate_percent => 15);

PL/SQL procedure successfully completed.

SQL> EXEC DBMS_STATS.gather_schema_stats('SCOTT', estimate_percent => 15, cascade => TRUE);

PL/SQL procedure successfully completed.

SQL> 
SQL> EXEC DBMS_STATS.gather_table_stats('HR', 'EMPLOYEES');

PL/SQL procedure successfully completed.

SQL> EXEC DBMS_STATS.gather_table_stats('HR', 'EMPLOYEES', estimate_percent => 15);

PL/SQL procedure successfully completed.

SQL> EXEC DBMS_STATS.gather_table_stats('HR', 'EMPLOYEES', estimate_percent => 15, cascade => TRUE);

PL/SQL procedure successfully completed.

SQL> 
SQL> 
SQL> EXEC DBMS_STATS.gather_dictionary_stats;

PL/SQL procedure successfully completed.

SQL> 

The ESTIMATE_PERCENT parameter was often used when gathering stats from large segments to reduce the sample size and therefore the overhead of the operation. In Oracle 9i upwards, we also had the option of letting Oracle determine the sample size using the AUTO_SAMPLE_SIZE constant, but this got a bad reputation because the selected sample size was sometimes inappropriate, making the resulting statistics questionable.

In Oracle 11g, the AUTO_SAMPLE_SIZE constant is the preferred (and default) sample size as the mechanism for determining the actual sample size has been improved. In addition, the statistics estimate based on the auto sampling are near to 100% accurate and much faster to gather than in previous versions, as described

The CASCADE parameter determines if statistics should be gathered for all indexes on the table currently being analyzed. Prior to Oracle 10g, the default was FALSE, but in 10g upwards it defaults to AUTO_CASCADE, which means Oracle determines if index stats are necessary.

As a result of these modifications to the behavior in the stats gathering, in Oracle 11g upwards, the basic defaults for gathering table stats are satisfactory for most tables.

Index statistics can be gathered explicitly using the GATHER_INDEX_STATS procedure.

SQL> EXEC DBMS_STATS.gather_index_stats('SCOTT', 'PK_EMP');

PL/SQL procedure successfully completed.

SQL> EXEC DBMS_STATS.gather_index_stats('SCOTT', 'PK_EMP', estimate_percent => 15);

PL/SQL procedure successfully completed.

SQL> show user;
USER is "SYS"
SQL> 

The current statistics information is available from the data dictionary views for the specific objects (DBA, ALL and USER views). Some of these view were added in later releases.

SQL> show user;
USER is "SYS"
SQL> desc DBA_TABLES
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 OWNER                                     NOT NULL VARCHAR2(128)
 TABLE_NAME                                NOT NULL VARCHAR2(128)
 TABLESPACE_NAME                                    VARCHAR2(30)
 CLUSTER_NAME                                       VARCHAR2(128)
 IOT_NAME                                           VARCHAR2(128)
 STATUS                                             VARCHAR2(8)
 PCT_FREE                                           NUMBER
 PCT_USED                                           NUMBER
 INI_TRANS                                          NUMBER
 MAX_TRANS                                          NUMBER
 INITIAL_EXTENT                                     NUMBER
 NEXT_EXTENT                                        NUMBER
 MIN_EXTENTS                                        NUMBER
 MAX_EXTENTS                                        NUMBER
 PCT_INCREASE                                       NUMBER
 FREELISTS                                          NUMBER
 FREELIST_GROUPS                                    NUMBER
 LOGGING                                            VARCHAR2(3)
 BACKED_UP                                          VARCHAR2(1)
 NUM_ROWS                                           NUMBER
 BLOCKS                                             NUMBER
 EMPTY_BLOCKS                                       NUMBER
 AVG_SPACE                                          NUMBER
 CHAIN_CNT                                          NUMBER
 AVG_ROW_LEN                                        NUMBER
 AVG_SPACE_FREELIST_BLOCKS                          NUMBER
 NUM_FREELIST_BLOCKS                                NUMBER
 DEGREE                                             VARCHAR2(10)
 INSTANCES                                          VARCHAR2(10)
 CACHE                                              VARCHAR2(5)
 TABLE_LOCK                                         VARCHAR2(8)
 SAMPLE_SIZE                                        NUMBER
 LAST_ANALYZED                                      DATE
 PARTITIONED                                        VARCHAR2(3)
 IOT_TYPE                                           VARCHAR2(12)
 TEMPORARY                                          VARCHAR2(1)
 SECONDARY                                          VARCHAR2(1)
 NESTED                                             VARCHAR2(3)
 BUFFER_POOL                                        VARCHAR2(7)
 FLASH_CACHE                                        VARCHAR2(7)
 CELL_FLASH_CACHE                                   VARCHAR2(7)
 ROW_MOVEMENT                                       VARCHAR2(8)
 GLOBAL_STATS                                       VARCHAR2(3)
 USER_STATS                                         VARCHAR2(3)
 DURATION                                           VARCHAR2(15)
 SKIP_CORRUPT                                       VARCHAR2(8)
 MONITORING                                         VARCHAR2(3)
 CLUSTER_OWNER                                      VARCHAR2(128)
 DEPENDENCIES                                       VARCHAR2(8)
 COMPRESSION                                        VARCHAR2(8)
 COMPRESS_FOR                                       VARCHAR2(30)
 DROPPED                                            VARCHAR2(3)
 READ_ONLY                                          VARCHAR2(3)
 SEGMENT_CREATED                                    VARCHAR2(3)
 RESULT_CACHE                                       VARCHAR2(7)
 CLUSTERING                                         VARCHAR2(3)
 ACTIVITY_TRACKING                                  VARCHAR2(23)
 DML_TIMESTAMP                                      VARCHAR2(25)
 HAS_IDENTITY                                       VARCHAR2(3)
 CONTAINER_DATA                                     VARCHAR2(3)
 INMEMORY                                           VARCHAR2(8)
 INMEMORY_PRIORITY                                  VARCHAR2(8)
 INMEMORY_DISTRIBUTE                                VARCHAR2(15)
 INMEMORY_COMPRESSION                               VARCHAR2(17)
 INMEMORY_DUPLICATE                                 VARCHAR2(13)
 DEFAULT_COLLATION                                  VARCHAR2(100)
 DUPLICATED                                         VARCHAR2(1)
 SHARDED                                            VARCHAR2(1)
 EXTERNAL                                           VARCHAR2(3)
 HYBRID                                             VARCHAR2(3)
 CELLMEMORY                                         VARCHAR2(24)
 CONTAINERS_DEFAULT                                 VARCHAR2(3)
 CONTAINER_MAP                                      VARCHAR2(3)
 EXTENDED_DATA_LINK                                 VARCHAR2(3)
 EXTENDED_DATA_LINK_MAP                             VARCHAR2(3)
 INMEMORY_SERVICE                                   VARCHAR2(12)
 INMEMORY_SERVICE_NAME                              VARCHAR2(1000)
 CONTAINER_MAP_OBJECT                               VARCHAR2(3)
 MEMOPTIMIZE_READ                                   VARCHAR2(8)
 MEMOPTIMIZE_WRITE                                  VARCHAR2(8)
 HAS_SENSITIVE_COLUMN                               VARCHAR2(3)
 ADMIT_NULL                                         VARCHAR2(3)
 DATA_LINK_DML_ENABLED                              VARCHAR2(3)
 LOGICAL_REPLICATION                                VARCHAR2(8)

SQL> DESC DBA_TAB_STATISTICS
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 OWNER                                              VARCHAR2(128)
 TABLE_NAME                                         VARCHAR2(128)
 PARTITION_NAME                                     VARCHAR2(128)
 PARTITION_POSITION                                 NUMBER
 SUBPARTITION_NAME                                  VARCHAR2(128)
 SUBPARTITION_POSITION                              NUMBER
 OBJECT_TYPE                                        VARCHAR2(12)
 NUM_ROWS                                           NUMBER
 BLOCKS                                             NUMBER
 EMPTY_BLOCKS                                       NUMBER
 AVG_SPACE                                          NUMBER
 CHAIN_CNT                                          NUMBER
 AVG_ROW_LEN                                        NUMBER
 AVG_SPACE_FREELIST_BLOCKS                          NUMBER
 NUM_FREELIST_BLOCKS                                NUMBER
 AVG_CACHED_BLOCKS                                  NUMBER
 AVG_CACHE_HIT_RATIO                                NUMBER
 IM_IMCU_COUNT                                      NUMBER
 IM_BLOCK_COUNT                                     NUMBER
 IM_STAT_UPDATE_TIME                                TIMESTAMP(9)
 SCAN_RATE                                          NUMBER
 SAMPLE_SIZE                                        NUMBER
 LAST_ANALYZED                                      DATE
 GLOBAL_STATS                                       VARCHAR2(3)
 USER_STATS                                         VARCHAR2(3)
 STATTYPE_LOCKED                                    VARCHAR2(5)
 STALE_STATS                                        VARCHAR2(7)
 NOTES                                              VARCHAR2(25)
 SCOPE                                              VARCHAR2(7)

SQL> DESC DBA_TAB_PARTITIONS
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 TABLE_OWNER                                        VARCHAR2(128)
 TABLE_NAME                                         VARCHAR2(128)
 COMPOSITE                                          VARCHAR2(3)
 PARTITION_NAME                                     VARCHAR2(128)
 SUBPARTITION_COUNT                                 NUMBER
 HIGH_VALUE                                         LONG
 HIGH_VALUE_LENGTH                                  NUMBER
 PARTITION_POSITION                                 NUMBER
 TABLESPACE_NAME                                    VARCHAR2(30)
 PCT_FREE                                           NUMBER
 PCT_USED                                           NUMBER
 INI_TRANS                                          NUMBER
 MAX_TRANS                                          NUMBER
 INITIAL_EXTENT                                     NUMBER
 NEXT_EXTENT                                        NUMBER
 MIN_EXTENT                                         NUMBER
 MAX_EXTENT                                         NUMBER
 MAX_SIZE                                           NUMBER
 PCT_INCREASE                                       NUMBER
 FREELISTS                                          NUMBER
 FREELIST_GROUPS                                    NUMBER
 LOGGING                                            VARCHAR2(7)
 COMPRESSION                                        VARCHAR2(8)
 COMPRESS_FOR                                       VARCHAR2(30)
 NUM_ROWS                                           NUMBER
 BLOCKS                                             NUMBER
 EMPTY_BLOCKS                                       NUMBER
 AVG_SPACE                                          NUMBER
 CHAIN_CNT                                          NUMBER
 AVG_ROW_LEN                                        NUMBER
 SAMPLE_SIZE                                        NUMBER
 LAST_ANALYZED                                      DATE
 BUFFER_POOL                                        VARCHAR2(7)
 FLASH_CACHE                                        VARCHAR2(7)
 CELL_FLASH_CACHE                                   VARCHAR2(7)
 GLOBAL_STATS                                       VARCHAR2(3)
 USER_STATS                                         VARCHAR2(3)
 IS_NESTED                                          VARCHAR2(3)
 PARENT_TABLE_PARTITION                             VARCHAR2(128)
 INTERVAL                                           VARCHAR2(3)
 SEGMENT_CREATED                                    VARCHAR2(4)
 INDEXING                                           VARCHAR2(4)
 READ_ONLY                                          VARCHAR2(4)
 INMEMORY                                           VARCHAR2(8)
 INMEMORY_PRIORITY                                  VARCHAR2(8)
 INMEMORY_DISTRIBUTE                                VARCHAR2(15)
 INMEMORY_COMPRESSION                               VARCHAR2(17)
 INMEMORY_DUPLICATE                                 VARCHAR2(13)
 CELLMEMORY                                         VARCHAR2(24)
 INMEMORY_SERVICE                                   VARCHAR2(12)
 INMEMORY_SERVICE_NAME                              VARCHAR2(1000)
 MEMOPTIMIZE_READ                                   VARCHAR2(8)
 MEMOPTIMIZE_WRITE                                  VARCHAR2(8)

SQL>
SQL> DESC DBA_TAB_COLUMNS
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 OWNER                                     NOT NULL VARCHAR2(128)
 TABLE_NAME                                NOT NULL VARCHAR2(128)
 COLUMN_NAME                               NOT NULL VARCHAR2(128)
 DATA_TYPE                                          VARCHAR2(128)
 DATA_TYPE_MOD                                      VARCHAR2(3)
 DATA_TYPE_OWNER                                    VARCHAR2(128)
 DATA_LENGTH                               NOT NULL NUMBER
 DATA_PRECISION                                     NUMBER
 DATA_SCALE                                         NUMBER
 NULLABLE                                           VARCHAR2(1)
 COLUMN_ID                                          NUMBER
 DEFAULT_LENGTH                                     NUMBER
 DATA_DEFAULT                                       LONG
 NUM_DISTINCT                                       NUMBER
 LOW_VALUE                                          RAW(2000)
 HIGH_VALUE                                         RAW(2000)
 DENSITY                                            NUMBER
 NUM_NULLS                                          NUMBER
 NUM_BUCKETS                                        NUMBER
 LAST_ANALYZED                                      DATE
 SAMPLE_SIZE                                        NUMBER
 CHARACTER_SET_NAME                                 VARCHAR2(44)
 CHAR_COL_DECL_LENGTH                               NUMBER
 GLOBAL_STATS                                       VARCHAR2(3)
 USER_STATS                                         VARCHAR2(3)
 AVG_COL_LEN                                        NUMBER
 CHAR_LENGTH                                        NUMBER
 CHAR_USED                                          VARCHAR2(1)
 V80_FMT_IMAGE                                      VARCHAR2(3)
 DATA_UPGRADED                                      VARCHAR2(3)
 HISTOGRAM                                          VARCHAR2(15)
 DEFAULT_ON_NULL                                    VARCHAR2(3)
 IDENTITY_COLUMN                                    VARCHAR2(3)
 SENSITIVE_COLUMN                                   VARCHAR2(3)
 EVALUATION_EDITION                                 VARCHAR2(128)
 UNUSABLE_BEFORE                                    VARCHAR2(128)
 UNUSABLE_BEGINNING                                 VARCHAR2(128)
 COLLATION                                          VARCHAR2(100)

SQL> DESC DBA_TAB_COL_STATISTICS
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 OWNER                                              VARCHAR2(128)
 TABLE_NAME                                         VARCHAR2(128)
 COLUMN_NAME                                        VARCHAR2(128)
 NUM_DISTINCT                                       NUMBER
 LOW_VALUE                                          RAW(2000)
 HIGH_VALUE                                         RAW(2000)
 DENSITY                                            NUMBER
 NUM_NULLS                                          NUMBER
 NUM_BUCKETS                                        NUMBER
 LAST_ANALYZED                                      DATE
 SAMPLE_SIZE                                        NUMBER
 GLOBAL_STATS                                       VARCHAR2(3)
 USER_STATS                                         VARCHAR2(3)
 NOTES                                              VARCHAR2(99)
 AVG_COL_LEN                                        NUMBER
 HISTOGRAM                                          VARCHAR2(15)
 SCOPE                                              VARCHAR2(7)

SQL> DESC DBA_PART_COL_STATISTICS
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 OWNER                                     NOT NULL VARCHAR2(128)
 TABLE_NAME                                NOT NULL VARCHAR2(128)
 PARTITION_NAME                                     VARCHAR2(128)
 COLUMN_NAME                                        VARCHAR2(4000)
 NUM_DISTINCT                                       NUMBER
 LOW_VALUE                                          RAW(2000)
 HIGH_VALUE                                         RAW(2000)
 DENSITY                                            NUMBER
 NUM_NULLS                                          NUMBER
 NUM_BUCKETS                                        NUMBER
 SAMPLE_SIZE                                        NUMBER
 LAST_ANALYZED                                      DATE
 GLOBAL_STATS                                       VARCHAR2(3)
 USER_STATS                                         VARCHAR2(3)
 NOTES                                              VARCHAR2(81)
 AVG_COL_LEN                                        NUMBER
 HISTOGRAM                                          VARCHAR2(15)

SQL> DESC DBA_SUBPART_COL_STATISTICS
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 OWNER                                     NOT NULL VARCHAR2(128)
 TABLE_NAME                                NOT NULL VARCHAR2(128)
 SUBPARTITION_NAME                                  VARCHAR2(128)
 COLUMN_NAME                                        VARCHAR2(4000)
 NUM_DISTINCT                                       NUMBER
 LOW_VALUE                                          RAW(2000)
 HIGH_VALUE                                         RAW(2000)
 DENSITY                                            NUMBER
 NUM_NULLS                                          NUMBER
 NUM_BUCKETS                                        NUMBER
 SAMPLE_SIZE                                        NUMBER
 LAST_ANALYZED                                      DATE
 GLOBAL_STATS                                       VARCHAR2(3)
 USER_STATS                                         VARCHAR2(3)
 NOTES                                              VARCHAR2(63)
 AVG_COL_LEN                                        NUMBER
 HISTOGRAM                                          VARCHAR2(15)

SQL> DESC DBA_INDEXES
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 OWNER                                     NOT NULL VARCHAR2(128)
 INDEX_NAME                                NOT NULL VARCHAR2(128)
 INDEX_TYPE                                         VARCHAR2(27)
 TABLE_OWNER                               NOT NULL VARCHAR2(128)
 TABLE_NAME                                NOT NULL VARCHAR2(128)
 TABLE_TYPE                                         VARCHAR2(11)
 UNIQUENESS                                         VARCHAR2(9)
 COMPRESSION                                        VARCHAR2(13)
 PREFIX_LENGTH                                      NUMBER
 TABLESPACE_NAME                                    VARCHAR2(30)
 INI_TRANS                                          NUMBER
 MAX_TRANS                                          NUMBER
 INITIAL_EXTENT                                     NUMBER
 NEXT_EXTENT                                        NUMBER
 MIN_EXTENTS                                        NUMBER
 MAX_EXTENTS                                        NUMBER
 PCT_INCREASE                                       NUMBER
 PCT_THRESHOLD                                      NUMBER
 INCLUDE_COLUMN                                     NUMBER
 FREELISTS                                          NUMBER
 FREELIST_GROUPS                                    NUMBER
 PCT_FREE                                           NUMBER
 LOGGING                                            VARCHAR2(3)
 BLEVEL                                             NUMBER
 LEAF_BLOCKS                                        NUMBER
 DISTINCT_KEYS                                      NUMBER
 AVG_LEAF_BLOCKS_PER_KEY                            NUMBER
 AVG_DATA_BLOCKS_PER_KEY                            NUMBER
 CLUSTERING_FACTOR                                  NUMBER
 STATUS                                             VARCHAR2(8)
 NUM_ROWS                                           NUMBER
 SAMPLE_SIZE                                        NUMBER
 LAST_ANALYZED                                      DATE
 DEGREE                                             VARCHAR2(40)
 INSTANCES                                          VARCHAR2(40)
 PARTITIONED                                        VARCHAR2(3)
 TEMPORARY                                          VARCHAR2(1)
 GENERATED                                          VARCHAR2(1)
 SECONDARY                                          VARCHAR2(1)
 BUFFER_POOL                                        VARCHAR2(7)
 FLASH_CACHE                                        VARCHAR2(7)
 CELL_FLASH_CACHE                                   VARCHAR2(7)
 USER_STATS                                         VARCHAR2(3)
 DURATION                                           VARCHAR2(15)
 PCT_DIRECT_ACCESS                                  NUMBER
 ITYP_OWNER                                         VARCHAR2(128)
 ITYP_NAME                                          VARCHAR2(128)
 PARAMETERS                                         VARCHAR2(1000)
 GLOBAL_STATS                                       VARCHAR2(3)
 DOMIDX_STATUS                                      VARCHAR2(12)
 DOMIDX_OPSTATUS                                    VARCHAR2(6)
 FUNCIDX_STATUS                                     VARCHAR2(8)
 JOIN_INDEX                                         VARCHAR2(3)
 IOT_REDUNDANT_PKEY_ELIM                            VARCHAR2(3)
 DROPPED                                            VARCHAR2(3)
 VISIBILITY                                         VARCHAR2(9)
 DOMIDX_MANAGEMENT                                  VARCHAR2(14)
 SEGMENT_CREATED                                    VARCHAR2(3)
 ORPHANED_ENTRIES                                   VARCHAR2(3)
 INDEXING                                           VARCHAR2(7)
 AUTO                                               VARCHAR2(3)
 CONSTRAINT_INDEX                                   VARCHAR2(3)

SQL> DESC DBA_IND_STATISTICS
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 OWNER                                              VARCHAR2(128)
 INDEX_NAME                                         VARCHAR2(128)
 TABLE_OWNER                                        VARCHAR2(128)
 TABLE_NAME                                         VARCHAR2(128)
 PARTITION_NAME                                     VARCHAR2(128)
 PARTITION_POSITION                                 NUMBER
 SUBPARTITION_NAME                                  VARCHAR2(128)
 SUBPARTITION_POSITION                              NUMBER
 OBJECT_TYPE                                        VARCHAR2(12)
 BLEVEL                                             NUMBER
 LEAF_BLOCKS                                        NUMBER
 DISTINCT_KEYS                                      NUMBER
 AVG_LEAF_BLOCKS_PER_KEY                            NUMBER
 AVG_DATA_BLOCKS_PER_KEY                            NUMBER
 CLUSTERING_FACTOR                                  NUMBER
 NUM_ROWS                                           NUMBER
 AVG_CACHED_BLOCKS                                  NUMBER
 AVG_CACHE_HIT_RATIO                                NUMBER
 SAMPLE_SIZE                                        NUMBER
 LAST_ANALYZED                                      DATE
 GLOBAL_STATS                                       VARCHAR2(3)
 USER_STATS                                         VARCHAR2(3)
 STATTYPE_LOCKED                                    VARCHAR2(5)
 STALE_STATS                                        VARCHAR2(3)
 SCOPE                                              VARCHAR2(7)

SQL> DESC DBA_IND_PARTITIONS
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 INDEX_OWNER                                        VARCHAR2(128)
 INDEX_NAME                                         VARCHAR2(128)
 COMPOSITE                                          VARCHAR2(3)
 PARTITION_NAME                                     VARCHAR2(128)
 SUBPARTITION_COUNT                                 NUMBER
 HIGH_VALUE                                         LONG
 HIGH_VALUE_LENGTH                                  NUMBER
 PARTITION_POSITION                                 NUMBER
 STATUS                                             VARCHAR2(8)
 TABLESPACE_NAME                                    VARCHAR2(30)
 PCT_FREE                                           NUMBER
 INI_TRANS                                          NUMBER
 MAX_TRANS                                          NUMBER
 INITIAL_EXTENT                                     NUMBER
 NEXT_EXTENT                                        NUMBER
 MIN_EXTENT                                         NUMBER
 MAX_EXTENT                                         NUMBER
 MAX_SIZE                                           NUMBER
 PCT_INCREASE                                       NUMBER
 FREELISTS                                          NUMBER
 FREELIST_GROUPS                                    NUMBER
 LOGGING                                            VARCHAR2(7)
 COMPRESSION                                        VARCHAR2(13)
 BLEVEL                                             NUMBER
 LEAF_BLOCKS                                        NUMBER
 DISTINCT_KEYS                                      NUMBER
 AVG_LEAF_BLOCKS_PER_KEY                            NUMBER
 AVG_DATA_BLOCKS_PER_KEY                            NUMBER
 CLUSTERING_FACTOR                                  NUMBER
 NUM_ROWS                                           NUMBER
 SAMPLE_SIZE                                        NUMBER
 LAST_ANALYZED                                      DATE
 BUFFER_POOL                                        VARCHAR2(7)
 FLASH_CACHE                                        VARCHAR2(7)
 CELL_FLASH_CACHE                                   VARCHAR2(7)
 USER_STATS                                         VARCHAR2(3)
 PCT_DIRECT_ACCESS                                  NUMBER
 GLOBAL_STATS                                       VARCHAR2(3)
 DOMIDX_OPSTATUS                                    VARCHAR2(6)
 PARAMETERS                                         VARCHAR2(1000)
 INTERVAL                                           VARCHAR2(3)
 SEGMENT_CREATED                                    VARCHAR2(3)
 ORPHANED_ENTRIES                                   VARCHAR2(3)

SQL>

Histogram information is available from the following views.

SQL> 
SQL> DESC DBA_TAB_HISTOGRAMS
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 OWNER                                              VARCHAR2(128)
 TABLE_NAME                                         VARCHAR2(128)
 COLUMN_NAME                                        VARCHAR2(4000)
 ENDPOINT_NUMBER                                    NUMBER
 ENDPOINT_VALUE                                     NUMBER
 ENDPOINT_ACTUAL_VALUE                              VARCHAR2(4000)
 ENDPOINT_ACTUAL_VALUE_RAW                          RAW(2000)
 ENDPOINT_REPEAT_COUNT                              NUMBER
 SCOPE                                              VARCHAR2(7)

SQL> DESC DBA_PART_HISTOGRAMS
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 OWNER                                              VARCHAR2(128)
 TABLE_NAME                                         VARCHAR2(128)
 PARTITION_NAME                                     VARCHAR2(128)
 COLUMN_NAME                                        VARCHAR2(4000)
 BUCKET_NUMBER                                      NUMBER
 ENDPOINT_VALUE                                     NUMBER
 ENDPOINT_ACTUAL_VALUE                              VARCHAR2(4000)
 ENDPOINT_ACTUAL_VALUE_RAW                          RAW(2000)
 ENDPOINT_REPEAT_COUNT                              NUMBER

SQL> DESC DBA_SUBPART_HISTOGRAMS
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 OWNER                                              VARCHAR2(128)
 TABLE_NAME                                         VARCHAR2(128)
 SUBPARTITION_NAME                                  VARCHAR2(128)
 COLUMN_NAME                                        VARCHAR2(4000)
 BUCKET_NUMBER                                      NUMBER
 ENDPOINT_VALUE                                     NUMBER
 ENDPOINT_ACTUAL_VALUE                              VARCHAR2(4000)
 ENDPOINT_ACTUAL_VALUE_RAW                          RAW(2000)
 ENDPOINT_REPEAT_COUNT                              NUMBER

SQL>

Table, column and index statistics can be deleted using the relevant delete procedures.

SQL> 
SQL> show user;
USER is "SYS"
SQL> EXEC DBMS_STATS.delete_database_stats;

PL/SQL procedure successfully completed.

SQL> EXEC DBMS_STATS.delete_table_stats('SCOTT', 'EMP');

PL/SQL procedure successfully completed.

SQL> EXEC DBMS_STATS.delete_table_stats('HR', 'EMPLOYEES');

PL/SQL procedure successfully completed.

SQL> EXEC DBMS_STATS.delete_column_stats('SCOTT', 'EMP', 'EMPNO');

PL/SQL procedure successfully completed.

SQL> EXEC DBMS_STATS.delete_index_stats('SCOTT', 'PK_EMP');

PL/SQL procedure successfully completed.

SQL> EXEC DBMS_STATS.delete_dictionary_stats;

PL/SQL procedure successfully completed.

SQL> 

System Stats

Introduced in Oracle 9iR1, the GATHER_SYSTEM_STATS procedure gathers statistics relating to the performance of your systems I/O and CPU. Giving the optimizer this information makes its choice of execution plan more accurate, since it is able to weigh the relative costs of operations using both the CPU and I/O profiles of the system.

There are two possible types of system statistics:

  • No workload: All databases come bundled with a default set of noworkload statistics, but they can be replaced with more accurate information. When gathering noworkload stats, the database issues a series of random I/Os and tests the speed of the CPU. As you can imagine, this puts a load on your system during the gathering phase.
SQL> 
SQL> EXEC DBMS_STATS.gather_system_stats;

PL/SQL procedure successfully completed.

SQL> 
  • Workload: When initiated using the start/stop or interval parameters, the database uses counters to keep track of all system operations, giving it an accurate idea of the performance of the system. If workload statistics are present, they will be used in preference to noworkload statistics.
SQL> 
SQL> -- Manually start and stop to sample a representative time (several hours) of system activity.
SQL> EXEC DBMS_STATS.gather_system_stats('start');

PL/SQL procedure successfully completed.

SQL> EXEC DBMS_STATS.gather_system_stats('stop');

PL/SQL procedure successfully completed.

SQL> 

SQL> 
SQL> -- Sample from now until a specific number of minutes.
SQL> 
SQL> EXEC DBMS_STATS.gather_system_stats('interval', interval => 180); 

PL/SQL procedure successfully completed.

SQL> 

Your current system statistics can be displayed by querying the AUX_STATS$ table.

SQL> show user;
USER is "SYS"
SQL> 
SQL> SELECT pname, pval1 FROM sys.aux_stats$ WHERE sname = 'SYSSTATS_MAIN';

PNAME                                                                                           PVAL1
------------------------------------------------------------------------------------------ ----------
CPUSPEEDNW                                                                                       3732
IOSEEKTIM                                                                                          10
IOTFRSPEED                                                                                       4096
SREADTIM                                                                                         .008
MREADTIM                                                                                          .02
CPUSPEED                                                                                         3733
MBRC                                                                                               10
MAXTHR
SLAVETHR

9 rows selected.

SQL> 

The DELETE_SYSTEM_STATS procedure will delete all workload stats and replace previously gathered noworkload stats with the default values.

SQL> 
SQL> show user;
USER is "SYS"
SQL> EXEC DBMS_STATS.delete_system_stats;

PL/SQL procedure successfully completed.

SQL> 

You only need to update your system statistics when something major has happened to your systems hardware or workload profile.

There are two schools of thought about system stats. One side avoid the use of system statistics altogether, favoring the default noworkload stats. The other side suggests providing accurate system statistics. The problem with the latter, is it is very difficult to decide what represents an accurate set of system statistics. Most people seem to favor investigation of systems using a variety of methods, including gathering system stats into a stats table, then manually setting the system statistics using the SET_SYSTEM_STATS procedure.

EXEC DBMS_STATS.set_system_stats('iotfrspeed', 4096);

Fixed Object Stats

Introduced in Oracle 10gR1, the GATHER_FIXED_OBJECTS_STATS procedure gathers statistics on the X$ tables, which sit underneath the V$ dynamic performance views. The X$ tables are not really tables at all, but a window on to the memory structures in the Oracle kernel. Fixed object stats are not gathered automatically, so you need to gather them manually at a time when the database is in a representative level of activity.

SQL> 
SQL> EXEC DBMS_STATS.gather_fixed_objects_stats;

PL/SQL procedure successfully completed.

SQL> 

Major changes to initialization parameters or system activity should signal you to gather fresh stats, but under normal running this does not need to be done on a regular basis.

The stats are removed using the DELETE_FIXED_OBJECTS_STATS procedure.

SQL> 
SQL> 
SQL> EXEC DBMS_STATS.delete_fixed_objects_stats;

PL/SQL procedure successfully completed.

SQL> 

Locking Stats

To prevent statistics being overwritten, you can lock the stats at schema, table or partition level.

SQL> 
SQL> EXEC DBMS_STATS.lock_schema_stats('SCOTT');

PL/SQL procedure successfully completed.

SQL> EXEC DBMS_STATS.lock_table_stats('SCOTT', 'EMP');

PL/SQL procedure successfully completed.

SQL> EXEC DBMS_STATS.lock_partition_stats('SCOTT', 'EMP', 'EMP_PART1');

PL/SQL procedure successfully completed.

If you need to replace the stats, they must be unlocked.

SQL> 
SQL> EXEC DBMS_STATS.unlock_schema_stats('SCOTT');

PL/SQL procedure successfully completed.

SQL> EXEC DBMS_STATS.unlock_table_stats('SCOTT', 'EMP');

PL/SQL procedure successfully completed.

SQL> EXEC DBMS_STATS.unlock_partition_stats('SCOTT', 'EMP', 'EMP_PART1');

PL/SQL procedure successfully completed.

Locking stats can be very useful to prevent automated jobs from changing them. This is especially useful with tables used for ETL processes. If the stats are gathered when the tables are empty, they will not reflect the real quantity of data during the load process. Instead, either gather stats each time the data is loaded, or gather them once on a full table and lock them.

Transfering Stats

It is possible to transfer statistics between servers allowing consistent execution plans between servers with varying amounts of data. First the statistics must be collected into a statistics table. In the following examples the statistics for the APPSCHEMA user are collected into a new table, STATS_TABLE, which is owned by DBASCHEMA.

EXEC DBMS_STATS.create_stat_table('DBASCHEMA','STATS_TABLE');
EXEC DBMS_STATS.export_schema_stats('APPSCHEMA','STATS_TABLE',NULL,'DBASCHEMA');

This table can then be transfered to another server using your preferred method (Export/Import, SQL*Plus COPY etc.) and the stats imported into the data dictionary as follows.

EXEC DBMS_STATS.import_schema_stats('APPSCHEMA','STATS_TABLE',NULL,'DBASCHEMA');
EXEC DBMS_STATS.drop_stat_table('DBASCHEMA','STATS_TABLE');

Setting Preferences

Since Oracle 10g, many of the default values of parameters for the DBMS_STATS procedures have changed from being hard coded to using preferences. In Oracle 10g, these preferences could be altered using the SET_PARAM procedure.

EXEC DBMS_STATS.set_param('DEGREE', '5');

In 11g, the SET_PARAM procedure was deprecated in favor of a layered approach to preferences. The four levels of preferences are amended with the following procedures.

  • SET_GLOBAL_PREFS: Used to set global preferences, including some specific to the automatic stats collection job.
  • SET_DATABASE_PREFS: Sets preferences for the whole database.
  • SET_SCHEMA_PREFS: Sets preferences for a specific schema.
  • SET_TABLE_PREFS: Sets preferences for a specific table.

The available preferences are listed below, along with the available scope (G=Global, D=Database, S=Schema, T=Table).

PreferenceDescriptionDefault (11gR2)ScopeVersion
CASCADEDetermines if index stats should be gathered for the current table (TRUE, FALSE, AUTO_CASCADE).DBMS_STATS.AUTO_CASCADEG, D, S, T10gR1+
DEGREEDegree of parallelism (integer or DEFAULT_DEGREE).DBMS_STATS.DEFAULT_DEGREEG, D, S, T10gR1+
ESTIMATE_PERCENTPercentage of rows to sample when gathering stats (0.000001-100 or AUTO_SAMPLE_SIZE).DBMS_STATS.AUTO_SAMPLE_SIZEG, D, S, T10gR1+
METHOD_OPTControls column statistics collection and histogram creation.FOR ALL COLUMNS SIZE AUTOG, D, S, T10gR1+
NO_INVALIDATEDetermines if dependent cursors should be invalidated as a result of new stats on objects (TRUE, FALSE or AUTO_INVALIDATE).DBMS_STATS.AUTO_INVALIDATEG, D, S, T10gR1+
AUTOSTATS_TARGETDetermines which objects have stats gathered (ALL, ORACLE, AUTO).AUTOG10gR2+
GRANULARITYThe granularity of stats to be collected on partitioned objects (ALL, AUTO, DEFAULT, GLOBAL, 'GLOBAL AND PARTITION', PARTITION, SUBPARTITION).AUTOG, D, S, T10gR2+
PUBLISHDetermines if gathered stats should be published immediately or left in a pending state (TRUE, FALSE).TRUEG, D, S, T11gR2+
INCREMENTALDetermines whether incremental stats will be used for global statistics on partitioned objects, rather than generated using table scans (TRUE, FALSE).FALSEG, D, S, T11gR2+
CONCURRENTShould objects statistics be gathered on multiple objects at once, or one at a time (MANUAL, AUTOMATIC, ALL, OFF).OFFG12cR1+
GLOBAL_TEMP_TABLE_STATSShould stats on global temporary tables be session-specific or shared between sessions (SHARED, SESSION).SESSIONG, D, S12cR1+
INCREMENTAL_LEVELWhich level of synopses should be collected for incremental partitioned statistics (TABLE, PARTITION).PARTITIONG, D, S, T12cR1+
INCREMENTAL_STALENESSHow is staleness of partition statistics determined (USE_STALE_PERCENT, USE_LOCKED_STATS, NULL).NULLG, D, S, T12cR1+
TABLE_CACHED_BLOCKSThe number of blocks cached in the buffer cache during calculation of index cluster factor. Jonathan Lewis recommends "16" as a sensible value.1G, D, S, T12cR1+
OPTIONSUsed for the OPTIONS parameter of the GATHER_TABLE_STATS procedure (GATHER, GATHER AUTO).GATHERG, D, S, T12cR1+

The following shows their basic usage.

EXEC DBMS_STATS.set_global_prefs('AUTOSTATS_TARGET', 'AUTO');
EXEC DBMS_STATS.set_database_prefs('STALE_PERCENT', '15');
EXEC DBMS_STATS.set_schema_prefs('SCOTT','DEGREE', '5');
EXEC DBMS_STATS.set_table_prefs('SCOTT', 'EMP', 'CASCADE', 'FALSE');

Global preferences can be reset and the other layers of preferences deleted using the following procedures.

EXEC DBMS_STATS.reset_global_pref_defaults;
EXEC DBMS_STATS.delete_database_prefs('CASCADE');
EXEC DBMS_STATS.delete_schema_prefs('SCOTT','DEGREE');
EXEC DBMS_STATS.delete_table_prefs('SCOTT', 'EMP', 'CASCADE');

Setting Stats Manually

The DBMS_STATS package provides several procedures for manually setting statistics.

  • SET_SYSTEM_STATS
  • SET_TABLE_STATS
  • SET_COLUMN_STATS
  • SET_INDEX_STATS

The current stats can be returned using the following procedures.

  • GET_SYSTEM_STATS
  • GET_TABLE_STATS
  • GET_COLUMN_STATS
  • GET_INDEX_STATS

Be careful when setting stats manually. Possibly the safest approach is to get the current values, amend them as required, then set them. An example of setting column statistics is shown below.

SET SERVEROUTPUT ON
DECLARE
  l_distcnt  NUMBER; 
  l_density  NUMBER;
  l_nullcnt  NUMBER; 
  l_srec     DBMS_STATS.StatRec;
  l_avgclen  NUMBER;
BEGIN
  -- Get current values.
  DBMS_STATS.get_column_stats (
    ownname => 'SCOTT', 
    tabname => 'EMP', 
    colname => 'EMPNO', 
    distcnt => l_distcnt, 
    density => l_density,
    nullcnt => l_nullcnt, 
    srec    => l_srec,
    avgclen => l_avgclen);

  -- Amend values.
  l_srec.minval := UTL_RAW.cast_from_number(7369);
  l_srec.maxval := UTL_RAW.cast_from_number(7934);

  -- Set new values.
  DBMS_STATS.set_column_stats (
    ownname => 'SCOTT', 
    tabname => 'EMP', 
    colname => 'EMPNO', 
    distcnt => l_distcnt, 
    density => l_density,
    nullcnt => l_nullcnt, 
    srec    => l_srec,
    avgclen => l_avgclen);
END;
/

Issues

  • Exclude dataload tables from your regular stats gathering, unless you know they will be full at the time that stats are gathered.
  • Prior to 10g, gathering stats for the SYS schema can make the system run slower, not faster.
  • Gathering statistics can be very resource intensive for the server so avoid peak workload times or gather stale stats only.
  • Even if scheduled, it may be necessary to gather fresh statistics after database maintenance or large data loads.

Legacy Methods for Gathering Database Stats

The information in this section is purely for historical reasons. All statistics management should now be done using the DBMS_STATS package.

Analyze Statement

The ANALYZE statement can be used to gather statistics for a specific table, index or cluster. The statistics can be computed exactly, or estimated based on a specific number of rows, or a percentage of rows.

ANALYZE TABLE employees COMPUTE STATISTICS;
ANALYZE INDEX employees_pk COMPUTE STATISTICS;

ANALYZE TABLE employees ESTIMATE STATISTICS SAMPLE 100 ROWS;
ANALYZE TABLE employees ESTIMATE STATISTICS SAMPLE 15 PERCENT;

DBMS_UTILITY

The DBMS_UTILITY package can be used to gather statistics for a whole schema or database. Both methods follow the same format as the analyze statement.

EXEC DBMS_UTILITY.analyze_schema('SCOTT','COMPUTE');
EXEC DBMS_UTILITY.analyze_schema('SCOTT','ESTIMATE', estimate_rows => 100);
EXEC DBMS_UTILITY.analyze_schema('SCOTT','ESTIMATE', estimate_percent => 15);

EXEC DBMS_UTILITY.analyze_database('COMPUTE');
EXEC DBMS_UTILITY.analyze_database('ESTIMATE', estimate_rows => 100);
EXEC DBMS_UTILITY.analyze_database('ESTIMATE', estimate_percent => 15);

Refreshing Stale Stats

This involves monitoring the DML operations against individual tables so statistics are only gathered for those tables whose data has changed significantly. This is the default action for the automatic optimizer statistics collection in 10g and above, but if you are using an older version of the database, you may want to read more about this here.

Scheduling Stats

Prior to Oracle 10g, scheduling the gathering of statistics using the DBMS_JOB package ws the easiest way to make sure they were always up to date.

SET SERVEROUTPUT ON
DECLARE
  l_job  NUMBER;
BEGIN
  DBMS_JOB.submit(l_job,
                  'BEGIN DBMS_STATS.gather_schema_stats(''SCOTT''); END;',
                  SYSDATE,
                  'SYSDATE + 1');
  COMMIT;
  DBMS_OUTPUT.put_line('Job: ' || l_job);
END;
/

The above code sets up a job to gather statistics for SCOTT for the current time every day. You can list the current jobs on the server using the DBA_JOBS and DBA_JOBS_RUNNING views.

Existing jobs can be removed using the following.

EXEC DBMS_JOB.remove(X);
COMMIT;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值