Oracle DBMS_STATS: Gather Schema and Table Statistics
Optimizing Performance with Oracle Database: Gathering Schema and Table Statistics
Purpose
Automatic optimizer statistics collection runs by itself inside the maintenance windows. Manual DBMS_STATS calls run when you decide, on the objects you choose, with the options you set. The SQL Tuning Guide names a different principal difference: automatic collection prioritizes the objects that need statistics. A DBA keeps a few manual commands ready for the cases the automatic job does not cover. The commands below gather statistics for one schema, for the SYS schema, and for one table.
Oracle stores optimizer statistics in the data dictionary. They describe the size and shape of tables, columns and indexes. The optimizer reads them to estimate how many rows a step will return, and then it picks the plan with the lowest cost. If the numbers are missing or old, the estimates are wrong, and the plan can be slow.
Most of the time the automatic job is enough. You run the manual commands in a few clear cases. One case is a bulk load that must be queried at once. Another is a volatile table that is deleted or truncated and then rebuilt during the day. The commands here stay at the schema and table level. Database-wide gathering is a separate call.
Code
1-- 1. Gather statistics for every object in one schema (default options)
2execute dbms_stats.gather_schema_stats('SCOTT');
3
4-- 2. Same schema, with the sample, the column option and the index option set
5execute dbms_stats.gather_schema_stats( -
6 ownname => 'SCOTT', -
7 estimate_percent => 1, -
8 method_opt => 'FOR ALL COLUMNS SIZE 1', -
9 cascade => TRUE);
10
11-- 3. Let the database choose the sample size
12execute dbms_stats.gather_schema_stats( -
13 ownname => 'SCOTT', -
14 cascade => TRUE, -
15 estimate_percent => dbms_stats.auto_sample_size);
16
17-- 4. The SYS schema (the owner of the data dictionary)
18execute dbms_stats.gather_schema_stats( -
19 ownname => 'SYS', -
20 cascade => TRUE);
21
22-- 5. One table
23exec dbms_stats.gather_table_stats('<owner>', '<table_name>');
Code Breakdown
The trailing - at the end of a line is the SQL*Plus continuation character. It lets one execute command run over several lines.
Statement 1: default schema gathering
gather_schema_stats('SCOTT') gathers statistics for all objects in the schema. The first argument is ownname. The Oracle reference says NULL for this argument means the current schema. Every other option uses its default.
Statement 2: explicit options
ownname => 'SCOTT'names the schema to analyze.estimate_percent => 1sets the share of rows to sample. The valid range is 0.000001 to 100. A value of 1 reads about one row in every hundred.method_opt => 'FOR ALL COLUMNS SIZE 1'controls column statistics and histograms. The documented default isFOR ALL COLUMNS SIZE AUTO. This example replaces that default with a fixed size clause of 1.cascade => TRUEgathers index statistics together with the table statistics. The reference says this is the same as runningGATHER_INDEX_STATSon each index in the schema.
Statement 3: automatic sample size
auto_sample_size is a constant, and you pass it as the value of estimate_percent. It is not a separate parameter. The reference says that with this constant the database decides the right sample size, and that this is the default. So you can also leave estimate_percent out and get the same result, as long as no ESTIMATE_PERCENT preference has been set with SET_DATABASE_PREFS, SET_GLOBAL_PREFS, SET_SCHEMA_PREFS or SET_TABLE_PREFS.
Statement 4: the SYS schema
The call is the same as for any other schema, but the privilege rule is different. For objects owned by SYS, you must own the object. Otherwise you need the ANALYZE ANY DICTIONARY privilege or the SYSDBA privilege. The Oracle SQL Tuning Guide also lists GATHER_DICTIONARY_STATS, which collects statistics for all system schemas, including SYS and SYSTEM.
Statement 5: one table
gather_table_stats takes the owner and the table name. It collects table, column and index statistics. Replace <owner> and <table_name> with real names before you run it.
Key Points
- Schema gathering and table gathering differ in scope and in options.
GATHER_SCHEMA_STATScovers all objects in a schema.GATHER_TABLE_STATScovers one table. Theoptionsparameter of the schema procedure also acceptsGATHER STALE,GATHER EMPTYand theLISTvalues, and it hasobjlistandobj_filter_list. The table procedure haspartnameandstattypeinstead. cascadedefaults toDBMS_STATS.AUTO_CASCADE. With that value, Oracle decides whether index statistics are needed. SettingTRUEforces them.- The calls end with a commit. The package reference says most procedures commit the current transaction, do the work, and commit again.
- Privileges matter. To run the schema procedure you must own the object, or hold the
ANALYZE ANYprivilege. - Statistics can be locked. Most procedures have a
forceparameter that overrides a lock on statistics. - Cursors may be invalidated. The
no_invalidateparameter decides what happens to cursors that depend on the object. The default lets Oracle choose when to invalidate them.
Insights and Best Practices
Prefer the automatic sample size
The Oracle documentation names AUTO_SAMPLE_SIZE as the default for estimate_percent. A fixed value such as 1 is a choice you make on purpose, for example to shorten a run on a very large schema. If you set it, compare plans before and after, because you have changed what the optimizer sees.
Know what the automatic job already does
By default, Oracle runs DBMS_STATS automatically to collect statistics for objects whose statistics are missing or stale. This runs inside the predefined maintenance windows. The SQL Tuning Guide says a monitored table is stale when it has been modified by more than 10 percent. Because of this, a manual run is not needed after every change. Check first whether the statistics are really old.
Gather only what is missing or stale
The options parameter of GATHER_SCHEMA_STATS accepts GATHER AUTO. With it, the call collects statistics only for objects that have none or whose statistics are stale. The default value, GATHER, gathers statistics on all objects in the schema.
1execute dbms_stats.gather_schema_stats( -
2 ownname => 'SCOTT', -
3 options => 'GATHER AUTO');
Use parallelism on large tables
The default for degree is NULL, which uses the degree set by the DEGREE clause on the table. The Oracle SQL Tuning Guide recommends DBMS_STATS.AUTO_DEGREE, which lets the database choose a degree from the object size and the parallel settings.
1execute dbms_stats.gather_table_stats( -
2 ownname => '<owner>', -
3 tabname => '<table_name>', -
4 degree => dbms_stats.auto_degree);
Choose a quiet time
Gathering reads your data, so it uses CPU and I/O. As a practical rule, run large manual jobs in a quiet period when few users are on the system.
Check results after the run
After a gather, look at the plans of your key queries. The goal is not fresh numbers for their own sake. What matters is that the statistics are representative of your data, not that they are new.
When to Run This
- After a bulk load, when queries must run before the maintenance window starts
- After large data loads or database maintenance, even when the automatic job is scheduled
- When a plan changed for the worse and the statistics on a table look old
- When a new schema or table was created and no one has gathered statistics yet
- When you tested a sampling change and want the same setting on one schema only
- When you need to refresh a single table without touching the rest of the schema
Troubleshooting Common Issues
ORA-20000. The reference lists this error for a schema or table that does not exist, or for insufficient privileges. Check the spelling of ownname and tabname. Then check that your account owns the object or has the ANALYZE ANY privilege.
ORA-20001. The reference lists this error for a bad input value. Check each argument. For example, estimate_percent must be between 0.000001 and 100.
Statistics did not change. The table may have its statistics locked. Most procedures in the package have a force parameter that overrides the lock. Use it only if you are sure the lock was not set on purpose.
A plan did not change after the run. By default, the database decides when to invalidate dependent cursors. The no_invalidate parameter controls this: FALSE invalidates them at once.
Missing statistics on a new object. The SQL Tuning Guide says statistics can be missing when an application creates new objects and does not call DBMS_STATS afterwards. If statistics are missing at parse time, the database may gather dynamic statistics. Those are lower in quality than statistics gathered with DBMS_STATS, so a manual gather is the better fix.
References
- DBMS_STATS, Oracle Database PL/SQL Packages and Types Reference 19c - The reference for
GATHER_SCHEMA_STATSandGATHER_TABLE_STATS: every parameter, default, privilege and error code used in this post. - Gathering Optimizer Statistics, SQL Tuning Guide 19c - Explains when to gather manually, the automatic job, stale statistics,
GATHER AUTOandAUTO_DEGREE. - Optimizer Statistics Concepts, SQL Tuning Guide 19c - Describes what optimizer statistics are and why the cost model needs them.
- Cost-Based Optimizer (CBO) And Database Statistics, ORACLE-BASE - Practical examples of schema and table gathering,
AUTO_SAMPLE_SIZE,cascade, and when to gather. - Useful gather statistics commands in Oracle, DBACLASS - Community examples of the same schema-level and table-level commands.
Posts in this series
- Oracle DBMS_STATS: Gather Schema and Table Statistics
- Oracle Statistics Gathering with DBMS_STATS Explained
- Oracle DBMS_STATS.GATHER_SYSTEM_STATS for Query Tuning
- Oracle DBMS_STATS: Delete Database Statistics
- Export/Import Oracle Optimizer Statistics: Complete Guide
- Oracle ANALYZE Statement: Table and Index Statistics
- Show a Count of Analyzed Tables by Schema in Oracle Database
- Oracle: Find Tables with Outdated Statistics via DBA_TABLES