oracledba.help
SpecialTopics

Statistics Gathering

The content here is derived from Doc IDs: 1337116.1, 377152.1 and 1233203.1.

Overview

Statistics on tables, indexes and partitions are used by the Cost Based Optimizer (CBO) in determining the most optimal way to execute SQL. In 12c and later an automatic statistics gathering job is created for every newly created database.

Oracle strongly recommends using the automatic statistics gathering feature as it liberates DBAs from the arduous tasks of determining:

  • Which objects need statistics.
  • The correct sampling percentages for objects.
  • Histogram bucket sizes based on the workload profile.
  • Degree of parallelism for statistics gathering.

If you find the Auto Stats job is not optimal for your needs you can disable it and update stats as you see fit.

Automatic Statistics Collection

Status

 SELECT CLIENT_NAME, STATUS 
 FROM DBA_AUTOTASK_CLIENT 
 WHERE CLIENT_NAME='auto optimizer stats collection';

 CLIENT_NAME                      STATUS
 -------------------------------  -------
 auto optimizer stats collection  ENABLED

Other Status Values: DISABLED,RETRY SCHEDULED,SCHEDULED,RUNNING,COMPLETED,BROKEN,FAILED,REMOTE,SUCCEEDED,CHAIN_STALLED

 -- dba_scheduler_programs
 COL owner        FORMAT a25
 COL program_name FORMAT a25
 SELECT owner, program_name, enabled FROM dba_scheduler_programs;

 OWNER            PROGRAM_NAME              ENABLE
 ---------------- ------------------------- ------
 SYS              GATHER_STATS_PROG         TRUE

-- Status of Stats Job Runs Last 24 Hours

COL CLIENT_NAME FORMAT a25
COL WINDOW_NAME FORMAT a15
COL WINDOW_START_TIME FORMAT a15
COL WINDOW_DURATION FORMAT a15
COL JOB_NAME FORMAT a15
COL JOB_STATUS FORMAT a10
COL JOB_START_TIME FORMAT a15
COL JOB_DURATION FORMAT a15
COL JOB_ERROR FORMAT 999999999
COL JOB_INFO FORMAT a15
SELECT 
    CLIENT_NAME, WINDOW_NAME, WINDOW_START_TIME, WINDOW_DURATION,
    JOB_NAME, JOB_STATUS, JOB_START_TIME, JOB_DURATION,
    JOB_ERROR, JOB_INFO
FROM 
    DBA_AUTOTASK_JOB_HISTORY
WHERE 
    CLIENT_NAME = 'auto optimizer stats collection'
    AND JOB_START_TIME >= SYSDATE - 1
ORDER BY 
    JOB_START_TIME DESC;

Disable

 exec DBMS_AUTO_TASK_ADMIN.DISABLE(
   client_name => 'auto optimizer stats collection', 
   operation => NULL, window_name => NULL);

exec DBMS_AUTO_TASK_ADMIN.DISABLE(client_name => 'auto optimizer stats collection',operation => NULL,window_name => NULL);

 -- dba_scheduler_programs
 EXEC DBMS_SCHEDULER.disable (name => 'GATHER_STATS_PROG');

Enable

 exec DBMS_AUTO_TASK_ADMIN.ENABLE(
   client_name => 'auto optimizer stats collection',
   operation => NULL, window_name => NULL);

exec DBMS_AUTO_TASK_ADMIN.ENABLE(client_name => 'auto optimizer stats collection',operation => NULL,window_name => NULL);

 -- dba_scheduler_programs
 EXEC DBMS_SCHEDULER.enable (name => 'GATHER_STATS_PROG');

History of Job Runs

 COL client_name       FORMAT a35
 COL window_name       FORMAT a25
 COL window_start_time FORMAT a35
 SELECT client_name, window_name, window_start_time
 FROM dba_autotask_job_history
 WHERE client_name='auto optimizer stats collection'
 ORDER BY  window_start_time;

Manually Run Job

 exec DBMS_AUTO_TASK_IMMEDIATE.GATHER_OPTIMIZER_STATS;

Put this in any script where you want to update the database stats.


Change Global Settings

Common change example:

 exec dbms_stats.set_global_prefs(pname=>'DEGREE',pvalue=>'10');
 exec dbms_stats.set_global_prefs(pname=>'STALE_PERCENT',pvalue=>'5');

 SELECT dbms_stats.get_prefs('DEGREE') FROM dual;
 10
 SELECT dbms_stats.get_prefs('STALE_PERCENT') FROM dual;
 5

Display Automatic Stats Gathering Job Parameters

SET ECHO OFF
SET TERMOUT ON
SET SERVEROUTPUT ON
SET TIMING OFF
DECLARE
   v1  varchar2(100);
   v2  varchar2(100);
   v3  varchar2(100);
   v4  varchar2(100);
   v5  varchar2(100);
   v6  varchar2(100);
   v7  varchar2(100);
   v8  varchar2(100);
   v9  varchar2(100);
   v10 varchar2(100);
BEGIN
   dbms_output.put_line('Automatic Stats Gathering Job - Parameters');
   dbms_output.put_line('==========================================');
   v1 := dbms_stats.get_prefs('AUTOSTATS_TARGET');
   dbms_output.put_line(' AUTOSTATS_TARGET:  ' || v1);
   v2 := dbms_stats.get_prefs('CASCADE');
   dbms_output.put_line(' CASCADE:           ' || v2);
   v3 := dbms_stats.get_prefs('DEGREE');
   dbms_output.put_line(' DEGREE:            ' || v3);
   v4 := dbms_stats.get_prefs('ESTIMATE_PERCENT');
   dbms_output.put_line(' ESTIMATE_PERCENT:  ' || v4);
   v5 := dbms_stats.get_prefs('METHOD_OPT');
   dbms_output.put_line(' METHOD_OPT:        ' || v5);
   v6 := dbms_stats.get_prefs('NO_INVALIDATE');
   dbms_output.put_line(' NO_INVALIDATE:     ' || v6);
   v7 := dbms_stats.get_prefs('GRANULARITY');
   dbms_output.put_line(' GRANULARITY:       ' || v7);
   v8 := dbms_stats.get_prefs('PUBLISH');
   dbms_output.put_line(' PUBLISH:           ' || v8);
   v9 := dbms_stats.get_prefs('INCREMENTAL');
   dbms_output.put_line(' INCREMENTAL:       ' || v9);
   v10:= dbms_stats.get_prefs('STALE_PERCENT');
   dbms_output.put_line(' STALE_PERCENT:     ' || v10);
END;
/

12c-19c default values.

 Automatic Stats Gathering Job - Parameters
 ==========================================
 AUTOSTATS_TARGET:  AUTO
 CASCADE:           DBMS_STATS.AUTO_CASCADE
 DEGREE:            NULL
 ESTIMATE_PERCENT:  DBMS_STATS.AUTO_SAMPLE_SIZE
 METHOD_OPT:        FOR ALL COLUMNS SIZE AUTO
 NO_INVALIDATE:     DBMS_STATS.AUTO_INVALIDATE
 GRANULARITY:       AUTO
 PUBLISH:           TRUE
 INCREMENTAL:       FALSE
 STALE_PERCENT:     10

Gather Schema Stats

 EXEC DBMS_STATS.GATHER_SCHEMA_STATS(
   ownname    => 'SCOTT', 
   degree     => DBMS_STATS.AUTO_DEGREE,
   cascade    => DBMS_STATS.AUTO_CASCADE,
   method_opt => 'FOR ALL COLUMNS SIZE AUTO',
   estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE);

Place on one line to execute.

  • degree: DBMS_STATS.AUTO_DEGREE or n (ex: 8).
  • estimate_percent : DBMS_STATS.AUTO_SAMPLE_SIZE or n (ex: 5).

Gather Table Stats

 EXEC DBMS_STATS.GATHER_TABLE_STATS(
   ownname    => 'SCOTT', 
   tabname    => 'MyTable', 
   degree     => DBMS_STATS.AUTO_DEGREE,
   cascade    => DBMS_STATS.AUTO_CASCADE,
   method_opt => 'FOR ALL COLUMNS SIZE AUTO',
   estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE);

Place on one line to execute.

  • degree: DBMS_STATS.AUTO_DEGREE or n (ex: 8).
  • estimate_percent : DBMS_STATS.AUTO_SAMPLE_SIZE or n (ex: 5).

Gather Dictionary Stats

According to Oracle, Dictionary stats should be updated every 6 months. Stats on system objects (via DBMS_STATS.GATHER_SYSTEM_STATS) are generally never needed (Doc ID 1501712.1).

 EXEC DBMS_STATS.GATHER_DICTIONARY_STATS;

Also see Doc ID 2100050.1 - How Does Dbms_Stats Gather_Dictionary_Stats and System Statistics?


Misc

Status of Running Stats Job

 SELECT to_char( max(last_analyzed), 'DD/MM/YYYY HH24:MI:SS') AS "last_analyzed" 
 FROM dba_tables;

 COL job_name  FORMAT a35
 COL log_date  FORMAT a35
 COL operation FORMAT a15
 COL status    FORMAT a15
 SELECT log_date,JOB_NAME,operation,status
 FROM dba_scheduler_job_log
 WHERE LOG_DATE > (sysdate-1/24)
 ORDER BY LOG_DATE;

Date Table Last Analyzed

 COL owner       FORMAT a15
 COL table_name  FORMAT a40
 COL STALE_STATS FORMAT a10
 SELECT owner,table_name,last_analyzed 
 FROM dba_tables 
 WHERE owner='SCOTT' 
 AND table_name='EMP';

Tables With Stale Statistics

 exec DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO;

 COL owner       FORMAT a15
 COL table_name  FORMAT a40
 COL STALE_STATS FORMAT a10
 SELECT OWNER,TABLE_NAME,to_char(LAST_ANALYZED,'yyyy.mm.dd hh24:mi'),STALE_STATS 
 FROM DBA_TAB_STATISTICS 
 WHERE STALE_STATS='YES'
 AND owner != 'SYS' 
 ORDER BY owner,table_name;

Running EXEC DBMS_STATS.GATHER_DICTIONARY_STATS; should reduce the number of SYS objects if there are a lot.

Statistics on Fixed Objects

 COL database_creation FORMAT a18
 COL last_analyzed     FORMAT a18
 SELECT dbid,to_char(created,'yyyy.mm.dd hh24:mi') database_creation,
   version,
   (select to_char(max(last_analyzed),'yyyy.mm.dd hh24:mi') last_analyzed 
    from dba_tab_statistics where object_type='FIXED TABLE') last_analyzed 
 FROM v$database,v$instance;

Manual Stats Update Session

 -- Disable Auto Stats Gathering
 EXEC DBMS_AUTO_TASK_ADMIN.DISABLE(client_name => 'auto optimizer stats collection',
      operation => NULL,window_name => NULL);
 EXEC DBMS_SCHEDULER.disable (name => 'GATHER_STATS_PROG');

 -- Ensure All Stats Updated For Given Data
 EXEC dbms_stats.delete_schema_Stats(OWNNAME => 'SCOTT'); 🠈 May take a few minutes.
 EXEC DBMS_STATS.set_schema_prefs('SCOTT','STALE_PERCENT',1);
 EXEC DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO;

 -- Update Stats
 EXEC DBMS_STATS.GATHER_SCHEMA_STATS(ownname => 'SCOTT', degree => 12,
      cascade => DBMS_STATS.AUTO_CASCADE, method_opt => 'FOR ALL COLUMNS SIZE AUTO',
      estimate_percent => 10);

 -- Reset to normal value locking in the stats (and available execution plans).
 EXEC dbms_stats.set_schema_prefs('SCOTT','STALE_PERCENT',10); 

 -- Re-enable Auto Stats Gathering (or not if you routinely manually update stats)
 EXEC DBMS_AUTO_TASK_ADMIN.ENABLE(client_name => 'auto optimizer stats collection',
      operation => NULL,window_name => NULL);
 EXEC DBMS_SCHEDULER.enable (name => 'GATHER_STATS_PROG');

All commands were executed on one line. Split here for ease of viewing.

Display Stale Stats

For Schema

SELECT RPAD(owner,15,' ') Owner, 
  RPAD(table_name,35,' ') Table_Name, 
  num_rows, 
  RPAD(TO_CHAR(last_analyzed,'DD-MON-YYYY HH24:MI:SS'),35,' ') last_analyzed 
FROM dba_tab_statistics
WHERE owner IN ('&Schema')
AND stale_stats='YES'
ORDER BY owner;

For Database

-- stats.stale.sql
-- Purpose: Locked stats in the database.

set verify off
COL owner       FORMAT a15
COL table_name  FORMAT a40
COL STALE_STATS FORMAT a10

prompt 
prompt +------------+
prompt |Stale Stats |
prompt +------------+
prompt 
--spool C:\oracle\scripts\spool\stale_stats.sql.spool

-- Process
SELECT OWNER,
      TABLE_NAME,
      to_char(LAST_ANALYZED,'yyyy.mm.dd hh24:mi') as LAST_ANALYZED,
      STALE_STATS 
FROM DBA_TAB_STATISTICS 
WHERE STALE_STATS='YES'
AND owner NOT IN('SYS','SYSTEM') 
ORDER BY owner,table_name;

-- End
prompt
--spool off