Prompt
Why is PostgreSQL CPU so high on my app database?
Latest observation
Oct 7, 2026
OpenAI APIWeb search: off
High PostgreSQL CPU usually means the database is spending most of its time executing queries or processing too many requests, rather than waiting on disk or network. The exact cause depends on the workload, but the common reasons are:
Common causes
1. Slow or inefficient queries
- Missing indexes
- Large table scans
- Bad join order
- Sorting/aggregation on large result sets
- Functions applied to indexed columns, preventing index use
2. Too many queries
- N+1 query patterns in the app
- Chatty application behavior
- Connection pool misconfiguration causing excessive concurrent work
- Background jobs running too aggressively
3. High concurrency / contention
- Many sessions competing for CPU
- Lock contention causing repeated retries
- Autovacuum or maintenance overlapping with app traffic
4. Expensive query plans
- Stale statistics
- Parameter-sensitive plans
- Bad estimates leading PostgreSQL to choose inefficient execution paths
5. Heavy write activity
- Frequent inserts/updates/deletes
- Index maintenance overhead
- HOT updates not possible due to schema/index design
6. Vacuum/autovacuum pressure
- Tables with lots of churn
- Dead tuples causing extra work
- Long-running transactions preventing cleanup
7. Connection overload
- Too many active connections
- Context switching overhead
- Each connection doing small bits of work inefficiently
How to find the exact cause
Start with the top queries
Use pg_stat_statements if enabled:
SELECT
query,
calls,
total_exec_time,
mean_exec_time,
rows
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 20;
Look for:
- high total time
- high average time
- high calls with small individual cost
Check active sessions
SELECT
pid, state, wait_event_type, wait_event,
now() - query_start AS running_for,
query
FROM pg_stat_activity
WHERE state <> 'idle'
ORDER BY running_for DESC;
Inspect query plans
For slow queries:
EXPLAIN (ANALYZE, BUFFERS)
SELECT ...;
Look for:
- sequential scans on large tables
- large sorts/hash operations
- rows estimate wildly different from actual rows
Check vacuum / bloat / stats
SELECT relname, n_dead_tup, n_live_tup
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC
LIMIT 20;
Typical fixes
- Add or improve indexes
- Rewrite expensive queries
- Reduce query count in the app
- Fix N+1 patterns
- Tune autovacuum
- Keep stats current with
ANALYZE - Reduce connection count with pooling
- Increase efficiency of bulk writes
If you want, I can help you diagnose it quickly
Send me any of these and I’ll help interpret them:
pg_stat_statementstop queriesEXPLAIN (ANALYZE, BUFFERS)for one slow querypg_stat_activityoutput during the CPU spike- Table sizes / index list for the busiest table
If you tell me your PostgreSQL version and a little about your app workload, I can narrow it down a lot.