Oracle after Hours: Gathering Statistics

Do you know what your database is doing after dark and on the weekends? What happens between 10 P.M. and 6 A.M. on weekdays, and all weekend? Would you be surprised to know that Oracle, by default, schedules a job to gather optimizer statistics upon creation of a database?

The name of the job is GATHER_STATS_JOB. Referencing the Performance Tuning Guide, this job is “created automatically at database creation time and is managed by the Scheduler. The Scheduler runs this job when the maintenance window is opened. By default, the maintenance window opens every night from 10 P.M. to 6 A.M. and all day on weekends.”

Let’s take a quick look at the Scott schema because that is typically created when a database is created. The first stop is to look at analyze information found in DBA_TABLES.

select table_name, to_char(liast_analyzed, ‘DD-MON-RR HH24:MI’)
“LAST DATE”, num_rows, sample_size
from dba_tables
where owner = ‘SCOTT’
order by last_analyzed;
—————————— —————- ———- ———–
DEPT 10-MAY-05 23:00 4 4
EMP 10-MAY-05 23:00 14 14
BONUS 10-MAY-05 23:00 0 0
SALGRADE 10-MAY-05 23:00 5 5

When was this database created? Assuming that this particular invocation of the Scott schema has not been touched or modified since it was created, does the date in LAST_DATE match the creation date of the database?

SQL> select name, to_char(created, ‘DD-MON-RR HH:MI:SS AM’) “WHEN”
2 from v$database;
——— ———————
PROD 10-MAY-05 10:35:22 AM

In this case, the answer is yes. If this job runs every night, then why is the LAST_DATE for Scott’s tables showing 10-MAY-05 and not something closer to today’s date (early October, 2006)? The reason is that Oracle considers Scott’s table data to be current (not stale), that is, less than 10% of the data (by table) has changed since the last time statistics were collected.

The specific mechanism or process which drives GATHER_STATS_JOB is DBMS_STATS.GATHER_DATABASE_STATS_JOB_PROC. The description of this is also given in the tuning guide:

The GATHER_DATABASE_STATS_JOB_PROC procedure collects statistics on database objects when the object has no previously gathered statistics or the existing statistics are stale because the underlying object has been modified significantly (more than 10% of the rows).The DBMS_STATS.GATHER_DATABASE_STATS_JOB_PROC is an internal procedure, but its operates in a very similar fashion to the DBMS_STATS.GATHER_DATABASE_STATS procedure using the GATHER AUTO option. The primary difference is that the DBMS_STATS.GATHER_DATABASE_STATS_JOB_PROC procedure prioritizes the database objects that require statistics, so that those objects which most need updated statistics are processed first. This ensures that the most-needed statistics are gathered before the maintenance window closes.

What does the GATHER_DATABASE_STATS_JOB_PROC do? Unfortunately, the package body is wrapped, so without access to the original source code, the implementation details are obscured. The DBMS_STATS package is created via the dbmsstat.sql script, and the package body (wrapped) is created via the prvtstat.plb script. Both scripts are found in the RDBMS/ADMIN directory under ORACLE_HOME.

Now that we know what is going on when, the next question concerns “how,” that is, how has the job been performing? The answer to this (and applies to other jobs as well) can be seen in DBA_SCHEDULER_JOBS.

JOB_NAME             START              STATE COUNT    COUNT LAST START       RUN TIME
——————– —————— —– —– ——- ——————- ——–
PURGE_LOG 11-AUG-04 03:00 AM SCHED 513 0 05-OCT-06 03:00 AM 00:00:00
GATHER_STATS_JOB SCHED 194 0 04-OCT-06 11:00 PM 06:23:54
ADV_SHRINK_1988719 SCHED 152 0 04-OCT-06 11:00 PM 00:00:04
ADV_SHRINK_2709655 SCHED 151 1 04-OCT-06 11:00 PM 01:39:04
MY_JOB 18-FEB-06 12:00 AM SCHED 244 24 05-OCT-06 04:00 AM 00:41:57
ADV_SHRINK_2457725 SCHED 151 0 04-OCT-06 11:00 PM 00:58:33
ADV_SQLACCESS2599661 SCHED 148 148 04-OCT-06 11:00 PM 00:00:00

The PURGE_LOG job has run 513 times since 11-AUG-04 and GATHER_STATS_JOB has 194 runs. The number of days does not add up, as the number of days between August, 2004 and October, 2006 is on the order of 770 plus days. One set of days which is fairly accurate is for MY_JOB at 244. At time of this article, there have been 230 days since 18-FEB-06, so the extra runs (both good and bad) are probably due to manual invocations (testing, ad hoc, etc.) of the job.

Recall that the nightly maintenance window is only eight hours, and the RUN TIME column shows that more than eight hours are required. It is possible that some jobs do not run because they are lower in priority (as determined by Oracle). There is an attribute/setting which may be the culprit of why a particular run count may off. As explained in the tuning guide:

The stop_on_window_close attribute controls whether the GATHER_STATS_JOB continues when the maintenance window closes. The default setting for the stop_on_window_close attribute is TRUE, causing Scheduler to terminate GATHER_STATS_JOB when the maintenance window closes.

The view also is telling in that it identifies jobs with serious problems (read as “does not work at all”) such as the SQL access advisory job at the bottom. If you don’t have alerts setup to notify you when a job succeeds (or fails), it is probably worthwhile to periodically inspect the STATE of a job via DBA_SCHEDULER_JOBS.

Another question related to “how” is how to enable or disable the automatic collection of statistics. The management of enabling/disabling the job is performed through the DBMS_SCHEDULER package. Chapter 27 of the Administrator’s Guide, “Using the Scheduler” of contains usage information.

Disabling a job, for example, is as simple as executing (in a PL/SQL block if you want) dbms_scheduler.disable(‘Enter_Job_Name’); in a SQL*Plus session (qualify with owner name if necessary). To disable the forever-failing ADV_SQLACCESS2599661 job (this is owned by SYS):

SQL> set serveroutput on
SQL> exec dbms_scheduler.disable(‘ADV_SQLACCESS2599661’);
PL/SQL procedure successfully completed.

No need to keep running a bad job, and the next steps are to find out who created it, is it necessary, and so on. The same step can be used on the GATHER_STATS_JOB if desired.

Are you stuck with the 10-6 and weekend schedule for GATHER_STATS_JOB? Let’s look at some of the details of the job via DBA_SCHEDULER_WINDOWS.

—————- ——————— ————————————-
WEEKNIGHT_WINDOW 05-OCT-06 10.00.00 PM Weeknight window for maintenance task
WEEKEND_WINDOW 07-OCT-06 12.00.00 AM Weekend window for maintenance task

The attribute that cannot be changed is WINDOW_NAME. Also included in Chapter 27 is information about altering a window. It is possible to increase or decrease the amount of time for the maintenance window.

You alter a window using the SET_ATTRIBUTE procedure or Enterprise Manager. With the exception of WINDOW_NAME, all the attributes of a window can be changed when it is altered. The attributes of a window are available in the *_SCHEDULER_WINDOWS views.

When a window is altered, it does not affect an active window. The changes only take effect the next time the window opens.

All windows can be altered. If you alter a window that is disabled, it will remain disabled after it is altered. An enabled window will be automatically disabled, altered, and then reenabled, if the validity checks performed during the enable process are successful.

In Closing

So now you know something about what your database is doing after hours. What else is going on that you may not know about, and how do you ensure that higher priority schemas (as opposed to what Oracle selects) always get analyzed in a maintenance window? The GATHER_STATS_JOB can be a valuable aid in optimizing performance if fed the right information, but you also have the option of creating your own (non-wrapped) gather statistics type of job and have it run in your own window.

» See All Articles by Columnist Steve Callan

Steve Callan
Steve Callan
Steve is an Oracle DBA (OCP 8i and 9i)/developer working in Denver. His Oracle experience also includes Forms and Reports, Oracle9iAS and Oracle9iDS.

Latest Articles