The optimizer cannot see your tables. It sees catalog statistics: row counts, column cardinalities, frequent values, index cluster ratios. The RUNSTATS online utility on DB2 for z/OS is how those numbers get there. Stale stats cause index skips, bad join order, and surprise tablespace scans. This page covers TABLESPACE, TABLE, and INDEX forms plus COLGROUP, sampling, SHRLEVEL, and profiles.
RUNSTATS gathers summary information about data in table spaces, indexes, and partitions. Db2 records the results in the catalog and uses them to select access paths during bind (static) and prepare (dynamic). You also query those catalog tables to decide when a REORG is due. Inline STATISTICS on REORG or LOAD can collect many of the same numbers without a separate RUNSTATS; a dedicated RUNSTATS is still the full-control tool.
| Form | Collects |
|---|---|
| RUNSTATS TABLESPACE | Space, optional tables, columns, indexes |
| … TABLE(name|ALL) | Table and column statistics for those tables |
| RUNSTATS INDEX | Index statistics only |
Phases are UTILINIT, RUNSTATS (scan and catalog update; extra sort subtasks for COLGROUP or certain FREQVAL), and UTILTERM.
123456789101112//RS EXEC PGM=DSNUTILB,PARM='DB2A,RSEMP' //STEPLIB DD DISP=SHR,DSN=DSN.SDSNLOAD //SYSPRINT DD SYSOUT=* //SYSIN DD * RUNSTATS TABLESPACE DBHR.TSEMP TABLE(ALL) INDEX(ALL) SHRLEVEL CHANGE REPORT YES UPDATE ALL HISTORY NONE /*
TABLE(ALL) or TABLE(creator.name) selects which tables in the space get column statistics. On a UTS there is one table; on a classic multi-table segmented space you can target one table or all.
Add column-level detail when the optimizer needs it:
123456789RUNSTATS TABLESPACE DBHR.TSEMP TABLE(HR.EMPLOYEE) COLGROUP(WORKDEPT, JOB) FREQVAL COUNT 10 MOST COLGROUP(SALARY) HISTOGRAM NUMQUANTILES 100 INDEX(ALL) FREQVAL NUMCOLS 1 COUNT 10 FREQVAL NUMCOLS 2 COUNT 10 SHRLEVEL CHANGE UPDATE ALL
FREQVAL COUNT 0 is the documented way to delete frequency statistics for that specification. Simply leaving FREQVAL off a later job does not remove old SYSCOLDIST rows.
1234RUNSTATS INDEX(HR.IXEMPNO) FREQVAL NUMCOLS 1 COUNT 10 SHRLEVEL CHANGE UPDATE ALL
NUMCOLS is the number of leading concatenated key columns. NUMCOLS 3 COUNT 10 alone does not give you frequencies for 1-col, 2-col, and 3-col prefixes — specify three FREQVAL clauses if you want all three. KEYCARD is deprecated; key cardinality is collected by default.
You can also hang INDEX(ALL) or named indexes off RUNSTATS TABLESPACE so one job collects both table and index stats.
ZPARM STATPGSAMP can force TABLESAMPLE SYSTEM AUTO for UTS and override SAMPLE. Use sampling to keep RUNSTATS inside the batch window; verify critical access paths after the first sampled run.
SHRLEVEL CHANGE allows read/write during the scan (slightly less consistent snapshot). REFERENCE is read-only for the duration.
| Option | Meaning |
|---|---|
| UPDATE ALL | Access-path and space statistics (common default intent) |
| UPDATE ACCESSPATH | Optimizer-facing statistics only |
| UPDATE SPACE | Space statistics (for REORG decisions) only |
| UPDATE NONE | Do not write the catalog; useful with REPORT YES |
REPORT YES writes a readable stats report to SYSPRINT even when UPDATE NONE. HISTORY can write a time series into history catalog tables; many shops use HISTORY NONE on daily jobs to avoid growth.
After UPDATE ACCESSPATH, SPACE, or ALL, rebind static packages that need the new numbers. Dynamic SQL depends on cache invalidation (INVALIDATECACHE YES where available).
Profiles in SYSIBM.SYSTABLES_PROFILES store the TABLE/INDEX/COLGROUP recipe. SET PROFILE or UPDATE PROFILE from a RUNSTATS statement, then later:
12345RUNSTATS TABLESPACE DBHR.TSEMP TABLE(HR.EMPLOYEE) USE PROFILE SHRLEVEL CHANGE UPDATE ALL
If no profile exists, USE PROFILE typically falls back to a COLUMN ALL / INDEX ALL style collection. From function level 507, USE PROFILE can also delete catalog statistics that are not in the profile, which is the supported cleanup for stale COLGROUPs. Do not let auto-updated profiles grow without review.
REORG TABLESPACE STATISTICS and LOAD STATISTICS collect many of the same columns. They are convenient after a full reload. They still follow the “only replace what you specified” rule. RUNSTATS remains the place for COLGROUP design, profiles, and index-only jobs.
RUNSTATS does not reorganize data, does not fix CHECK-pending, and does not collect clone statistics. Inaccurate stats can even cause sort failures in CHECK INDEX — keep stats current on large objects you check.
The optimizer is a cook who never walks into the pantry. RUNSTATS is the person who counts the apples, notes that most of them are Granny Smith, and writes the numbers on a chalkboard (the catalog). If nobody updates the chalkboard after a huge delivery, the cook still plans a recipe for “twelve apples” and dinner goes wrong. COLGROUP is counting “apples and cinnamon together.” FREQVAL is “the ten most common apple types.” TABLESAMPLE is tasting every tenth crate instead of every apple when the pantry is enormous.
1. What does RUNSTATS record, and who uses it?
2. What is the difference between RUNSTATS TABLESPACE and RUNSTATS INDEX?
3. Does omitting FREQVAL on a later RUNSTATS delete old frequencies?
4. KEYCARD on RUNSTATS INDEX means what today?
5. After RUNSTATS UPDATE ALL, what should you do for static SQL?