PostgreSQL Database Statistics with pg_stat_database
Monitor PostgreSQL Databases with pg_stat_database
PostgreSQL tracks activity at the database level in the pg_stat_database view. Every database on the server has a row, and each row contains counters for commits, rollbacks, cache hits, disk reads, deadlocks, temp file usage, and more. This is one of the first places to look when you need a quick health check across all databases.
A simple SELECT * returns everything, but the view has over 30 columns. The query below selects the most actionable columns and formats them for easy reading.
Sample Code
1SELECT
2 datname AS database,
3 numbackends AS connections,
4 xact_commit AS commits,
5 xact_rollback AS rollbacks,
6 ROUND(blks_hit::numeric / NULLIF(blks_hit + blks_read, 0) * 100, 2)
7 AS cache_hit_pct,
8 blks_read,
9 blks_hit,
10 tup_returned,
11 tup_fetched,
12 tup_inserted,
13 tup_updated,
14 tup_deleted,
15 conflicts,
16 deadlocks,
17 temp_files,
18 pg_size_pretty(temp_bytes) AS temp_size,
19 stats_reset
20FROM
21 pg_stat_database
22WHERE
23 datname IS NOT NULL
24ORDER BY
25 numbackends DESC;
Notes: Works on all supported PostgreSQL versions. The datname IS NOT NULL filter excludes internal rows for shared objects. Counters accumulate since the last pg_stat_reset() call or server restart. Run SELECT pg_stat_reset() within a specific database to reset its counters.
Code Breakdown
pg_stat_database— A system view with one row per database (plus one for shared objects). Populated by the statistics collector.numbackends— The number of active client connections to this database right now. Unlike other columns, this is a live count, not a cumulative counter.xact_commit— Total transactions committed since the last reset. A healthy workload shows this growing steadily.xact_rollback— Total transactions rolled back. A high rollback rate relative to commits may indicate application errors or frequent transaction conflicts.blks_hit/blks_read— Blocks served from the shared buffer cache vs blocks read from disk. The cache hit percentage is derived from these two values.NULLIF(blks_hit + blks_read, 0)— Prevents division by zero on a database with no activity.tup_returned— Rows returned by sequential scans and index scans. A high value relative totup_fetchedcan indicate over-scanning (too many sequential scans returning more rows than needed).tup_fetched— Rows actually fetched by index scans. A high ratio oftup_fetchedtotup_returnedis a sign of efficient index use.conflicts— Queries canceled on standby due to conflicts with recovery. Relevant only on hot standby replicas.deadlocks— Total deadlocks detected. Any non-zero value warrants investigation.temp_files/temp_bytes— Number of temporary files created and their total size. Temp files are written when a sort or hash operation exceedswork_mem.stats_reset— The timestamp of the last counter reset for this database.
Key Points
- Sort by
numbackends DESCto see the most active databases first. Sort bydeadlocks DESCortemp_files DESCto surface problem databases. - A cache hit percentage below 95% suggests the database is reading too much from disk. Consider increasing
shared_buffersor adding indexes to reduce full table scans. - Growing
temp_filesvalues mean queries are spilling to disk. Increasingwork_memfor those sessions can eliminate temp file writes, at the cost of more memory per connection.
Insights and Explanations
Cache hit ratio:
The cache hit ratio is the percentage of block reads served from shared_buffers rather than from disk. A well-tuned OLTP database typically runs at 99% or higher. If you see a database consistently below 95%, it may be underconfigured for memory, running full table scans that should be index scans, or handling a workload that genuinely requires a lot of disk I/O.
Rollback ratio:
Calculate the rollback ratio as xact_rollback / (xact_commit + xact_rollback). A ratio above 1–2% is worth investigating. Common causes include application-level errors that trigger rollbacks, explicit ROLLBACK calls in error handlers, or lock timeouts.
Deadlocks:
Deadlocks in PostgreSQL are detected automatically and one of the involved transactions is canceled. A non-zero deadlock count does not mean the database is broken, but it does mean application transactions are acquiring locks in conflicting orders. Check pg_log for ERROR: deadlock detected entries to identify the queries involved.
Additional Considerations
- Permissions: Superusers see all rows. Regular users see only databases they have
CONNECTpermission on, plus a row for their own database. - Counter resets: Counters reset on server restart and when
pg_stat_reset()is called. Thestats_resetcolumn shows when the last reset happened, which is important context for interpreting counts. - Shared objects row: The row where
datname IS NULLcontains statistics for shared system catalogs. The filter in this query excludes it, but you can remove theWHEREclause to include it.
References
Posts in this series
- How Many Connections Can Your PostgreSQL Database Handle?
- PostgreSQL Backend Connections via pg_stat_database
- Identifying Blocking PostgreSQL Queries using pg_stat_activity
- List PostgreSQL Databases by Size with Access Check
- Assess PostgreSQL Database Sizes Quickly and Easily
- Unveiling Your PostgreSQL Server - A Diagnostic Powerhouse
- Keep Your PostgreSQL Database Clean, Identify Idle Connections
- Query the PostgreSQL Configuration
- PostgreSQL Recovery Monitoring: Essential SQL Insights
- Restart All PostgreSQL Sequences with ALTER SEQUENCE
- Monitor Running Queries in PostgreSQL using pg_stat_activity
- Monitor PostgreSQL Active Sessions with pg_stat_activity
- PostgreSQL Error Handling Settings via pg_settings
- PostgreSQL File Location Settings Query via pg_settings
- PostgreSQL Lock Management Settings via pg_settings
- PostgreSQL Logging Configuration Query via pg_settings
- Monitor PostgreSQL Memory Settings with pg_settings
- PostgreSQL Table Row Count Estimates with SQL
- List PostgreSQL Tables by Size with SQL
- PostgreSQL WAL Settings Query Guide
- PostgreSQL SSL Settings Query Guide
- PostgreSQL Statistics Settings Query Guide
- PostgreSQL Resource Settings Query Guide
- PostgreSQL Replication Settings Query Guide
- PostgreSQL Query Planning Settings Query Guide
- PostgreSQL Preset Options Settings Query Guide
- PostgreSQL Miscellaneous Settings Query Guide
- Count PostgreSQL Sessions by State with SQL
- Kill Idle PostgreSQL Sessions with SQL
- Grant SELECT on All Tables in PostgreSQL
- Identify Insert-Only Tables in PostgreSQL
- Detect Soft Delete Patterns in PostgreSQL
- List PostgreSQL Object Comments with SQL
- List Foreign Key Constraints in PostgreSQL
- List PostgreSQL Enum Types and Their Values with SQL
- List All Views in a PostgreSQL Database with SQL
- Find PostgreSQL Tables Without a Primary Key
- List PostgreSQL Partitioned Tables with SQL
- List All Schemas in Your PostgreSQL Database
- PostgreSQL Database Statistics with pg_stat_database
- Scrubbing Email PII in PostgreSQL for GDPR Compliance