List Database Peak Usage with DBA_HIGH_WATER_MARK_STATISTICS
List Database Peak Usage with DBA_HIGH_WATER_MARK_STATISTICS
Purpose
DBA_HIGH_WATER_MARK_STATISTICS stores the peak value of a set of counters for database size and load. It also stores the value seen at the last sample. Each row is one statistic. Two examples are the maximum number of concurrent sessions (SESSIONS) and the maximum size of the database in bytes (DB_SIZE).
Each row also carries the database version in which the mark was tracked. This means one statistic name can have rows for more than one version. The script returns one row per statistic name, taken from the newest version. Each row shows the high-water value and the last value.
A DBA runs it to read the largest size the database has reached and the most concurrent sessions it has seen.
Code
1COLUMN name FORMAT A40
2COLUMN highwater FORMAT 999999999999
3COLUMN last_value FORMAT 999999999999
4SET PAGESIZE 24
5
6SELECT hwm1.name,
7 hwm1.highwater,
8 hwm1.last_value
9FROM dba_high_water_mark_statistics hwm1
10WHERE hwm1.version = (SELECT MAX(hwm2.version)
11 FROM dba_high_water_mark_statistics hwm2
12 WHERE hwm2.name = hwm1.name)
13ORDER BY hwm1.name;
14
15COLUMN FORMAT DEFAULT
Code Breakdown
COLUMN name FORMAT A40makes the statistic name column 40 characters wide.COLUMN highwater FORMAT 999999999999andCOLUMN last_value FORMAT 999999999999give each number column 12 digits. That fits counts of sessions, files and tables.DB_SIZEandSEGMENT_SIZEare stored in bytes, and a value of 10^12 bytes (about 931 GiB) or more has 13 digits. When a value does not fit, SQL*Plus displays pound signs (#) in place of the number. The fix is in "Widen the format for byte statistics".- The
COLUMNcommands use the bare nameshighwaterandlast_value, but the query selectshwm1.highwaterandhwm1.last_value. The formats still apply.hwm1.is a table prefix (an alias), andCOLUMNignores table name prefixes inSELECTcommands. SET PAGESIZE 24sets the output page size. The script does not set it back at the end.SELECT hwm1.name, hwm1.highwater, hwm1.last_valuereturns three values for each row: the statistic name, the highest value of the statistic seen at sampling time, and the value at the last sample time. The script does not selectDBID,VERSIONorDESCRIPTION.WHERE hwm1.version = (SELECT MAX(hwm2.version) ...)is a correlated subquery. For each row in the outer query, it finds the highestVERSIONstored for the sameNAME. Only rows at that version are kept, so older rows from before an upgrade drop out.VERSIONis aVARCHAR2(17)column.MAXon a text column compares characters from left to right. Text order matches release order only while every version string starts with a release number of the same length. Check the storedVERSIONvalues once on your own system before you trust the order (see Troubleshooting).- The subquery matches on
NAMEonly. It does not match onDBID, the identifier of the database the statistics belong to. If the view holds rows for more than oneDBID, the subquery takes the highest version across all of them. EveryDBIDthat has a row at that version then returns its own row, and the same name appears twice. ORDER BY hwm1.namesorts the output by statistic name.COLUMN FORMAT DEFAULTis the last line. It does not namename,highwaterorlast_value.CLEAR COLUMNSresets the attributes of all columns. AddCLEAR COLUMNSat the end of your local copy, or run it after the script, so the column formats do not carry into the next query.
What the main statistics mean (19c)
| Name | Meaning |
|---|---|
DB_SIZE | Maximum size of the database, in bytes |
SEGMENT_SIZE | Size of the largest segment, in bytes |
SESSIONS | Maximum number of concurrent sessions seen in the database |
ACTIVE_SESSIONS | Maximum number of active sessions seen in the system |
CPU_COUNT | Maximum number of CPUs |
INSTANCES | Oracle Database instances |
DATAFILES | Maximum number of datafiles |
TABLESPACES | Maximum number of tablespaces |
EXADATA_DISKS | Number of physical disks |
QUERY_LENGTH | Maximum query length |
PART_TABLES | Maximum number of partitions in one user table |
SQL_NCHAR_COLUMNS | Maximum number of SQL NCHAR columns |
USER_TABLES | Number of user tables |
USER_INDEXES | Number of user indexes |
USER_MV | Maximum number of materialized views (user) |
Key Points
- The view is documented from Oracle Database 10g Release 1 (10.1) onward, with its
HIGHWATERandLAST_VALUEcolumns. The script sits in a folder named10gin its repository. - The list of statistics changes between releases. The 10.1 list includes
SERVICES(maximum number of services), and the 19c list does not.ACTIVE_SESSIONS,EXADATA_DISKS,INSTANCES,SQL_NCHAR_COLUMNSandUSER_MVare in the 19c list, and none of these five is in the 10.1 list. Two databases on different releases therefore return different sets of rows. - The script does not select
DESCRIPTION, so its output does not change when that column grows toVARCHAR2(4000)in release 26, up fromVARCHAR2(128)in 10.1 and 19c. Release 26 also describesINSTANCESas "Oracle AI Database instances". - The segment high water mark is a separate concept with a similar name. A segment HWM is the point in a segment beyond which blocks are unformatted and have never been used. It drops only after you rebuild, truncate or shrink the object. This view stores database-wide peaks such as size, sessions and CPUs.
V$LICENSEalso has high-water columns, but they count from instance startup:SESSIONS_HIGHWATER,CPU_COUNT_HIGHWATERandCPU_CORE_COUNT_HIGHWATER. A restart starts them again.
Insights and Best Practices
Compare HIGHWATER with LAST_VALUE
HIGHWATER is the highest value seen at sampling time, and LAST_VALUE is the value at the last sample. When HIGHWATER is far above LAST_VALUE, the peak was recorded at an earlier sample. The view has no date column, so it cannot tell you when that peak was recorded.
Pair with feature usage
A license review asks two questions: how big and busy the database is, and which features it uses. This script answers the first. DBA_FEATURE_USAGE_STATISTICS answers the second. This query lists only the features with at least one detection:
1SELECT name, version, detected_usages, total_samples,
2 currently_used, first_usage_date, last_usage_date,
3 last_sample_date
4FROM dba_feature_usage_statistics
5WHERE detected_usages > 0
6ORDER BY name, version;
DETECTED_USAGESis the number of times the system detected usage of the feature.TOTAL_SAMPLESis the number of times the system woke up and checked. Read the two together. A feature detected in 1 of 200 samples was seen once. A feature detected in 200 of 200 samples was seen at every check.CURRENTLY_USEDisTRUEonly if usage was detected the last time the system checked. AFALSEvalue says nothing about earlier samples.FIRST_USAGE_DATEandLAST_USAGE_DATEare sample times: the first and last checks that detected usage.LAST_SAMPLE_DATEis the last time the system checked for usage.- Like the high-water view, this view has
DBIDandVERSIONcolumns. One feature can have a row for each release in which it was tracked.
Widen the format for byte statistics
In a local copy, edit the two number COLUMN lines so each format has more 9s than the digit count of your largest byte value. Each 9 is one digit, so FORMAT 999999999999999 (15 nines) shows values up to 999,999,999,999,999 bytes.
For a number column, a COLUMN FORMAT setting takes precedence over SET NUMFORMAT, and SET NUMFORMAT takes precedence over SET NUMWIDTH. The script sets COLUMN FORMAT, so changing NUMFORMAT or NUMWIDTH for the session leaves the width as it is. Edit the COLUMN lines.
To read a byte value in GiB, divide it by 1024 three times in a separate query, for example ROUND(highwater/1024/1024/1024, 1). Leave the script's own columns in bytes so the output matches the view.
Read the older version rows after an upgrade
The script hides rows from earlier versions on purpose. To see every row, drop the WHERE clause and add DBID, VERSION and DESCRIPTION:
1COLUMN description FORMAT A50
2SELECT dbid, name, version, highwater, last_value, description
3FROM dba_high_water_mark_statistics
4ORDER BY name, version, dbid;
Each statistic name now shows one row for each version in which it was tracked, and one for each DBID. Use this output to compare a statistic across the releases the database has run, and to see which rows the MAX(version) filter kept. DESCRIPTION carries the meaning of each statistic, so a name you do not know is explained in the same output.
When to Run This
- On a fixed schedule. Save the output and compare
DB_SIZE,SEGMENT_SIZE,DATAFILESandTABLESPACESwith the copy from the last run to measure growth. - Before a license review. Read the
CPU_COUNTandSESSIONSrows and the feature usage query together, so you know what the dictionary records. - After a migration or upgrade. Confirm which
VERSIONthe script picked, and run the query in "Read the older version rows after an upgrade" to compare both releases.
Troubleshooting Common Issues
- ORA-00942: table or view does not exist. The connected user cannot see the view. Run the script as a user who can read
DBA_HIGH_WATER_MARK_STATISTICS, or have that access granted. - Pound signs in HIGHWATER or LAST_VALUE. See "Widen the format for byte statistics".
- The same name appears twice. If the view holds rows for more than one
DBIDat the same version, the script returns one row for each. Run the query from "Read the older version rows after an upgrade" to see whichDBIDeach row belongs to. Then filter on theDBIDof the database you are reviewing. - NULL core or socket counts in V$LICENSE.
V$LICENSEreturnsNULLwhen a statistic is not available on the operating system platform. ANULLinCPU_CORE_COUNT_HIGHWATERmeans the platform did not supply a core count.V$LICENSEkeeps logical CPUs (CPU_COUNT_HIGHWATER) and cores (CPU_CORE_COUNT_HIGHWATER) in separate columns. The high-water view defines itsCPU_COUNTstatistic only as "Maximum Number of CPUs". - The script picks the wrong version. Run the same query for one statistic, such as
SESSIONS. If the text order of theVERSIONvalues does not match release order, filter on the exact version you need in place ofMAX. - Feature usage rows look out of date. Check
LAST_SAMPLE_DATEfirst. If it is far in the past, the system has not checked for usage since then, andCURRENTLY_USEDdescribes that old check.
References
- DBA_HIGH_WATER_MARK_STATISTICS, Oracle Database 19c Reference - column definitions and the 19c list of statistic names and meanings
- DBA_HIGH_WATER_MARK_STATISTICS, Oracle Database Reference release 26 - the wider DESCRIPTION column and the reworded INSTANCES statistic
- DBA_HIGH_WATER_MARK_STATISTICS, Oracle Database 10g Release 1 Reference - the view as documented in 10.1, and the 10.1 statistic list, including SERVICES
- V$LICENSE, Oracle Database 19c Reference - high-water columns since instance startup, separate logical CPU and core columns, and NULL values
- DBA_FEATURE_USAGE_STATISTICS, Oracle Database 19c Reference - the companion view and its sampling columns
- COLUMN, SQL*Plus User's Guide and Reference 19c - pound-sign overflow, the 9 format digit, format precedence, table name prefixes and CLEAR COLUMNS
- Logical Storage Structures, Oracle Database 19c Concepts - the segment high water mark, a different concept
- oraclebase/dba: 10g/db_usage_hwm.sql on GitHub - the source script by Tim Hall, last modified 26-NOV-2004, in a GPL-3.0 licensed repository
- db_usage_hwm.sql on oracle-base.com - the same script, published as a plain SQL file
Posts in this series
- Determining Oracle Database Startup Time using v$instance
- Oracle Schema Space Usage with dba_segments and dba_objects
- Check if Java is Installed in Oracle Database
- Oracle Top 10 Largest Segments Query with dba_segments
- Oracle Feature Usage with dba_feature_usage_statistics
- Assessing Database Storage Utilization in Oracle Database
- Unveiling Language and Locale Settings in Oracle Database
- Locate the Alert Log and Trace Files with V$DIAG_INFO
- List Database Peak Usage with DBA_HIGH_WATER_MARK_STATISTICS