Production
72
Health score
Cache
95
99.2% buffer, 98.8% index
Indexes
60
6 unused (48.0 MB)
Bloat
55
12.5% bloat ratio
Queries
100
No long-running queries
Vacuum
68
7.2% dead tuples
Connections
100
18/100 (18.0%)
Health trend
Recommendations 3
▸
Warning
Indexes
6 unused indices wasting 48.0 MB
These indexes have had 0 scans since stats were last reset. Every write (INSERT/UPDATE/DELETE) still pays the cost of maintaining them. Stats have been accumulating for 21.0 days — reliable enough to act on, but always verify on production.
What to do
Generate ready-to-run DROP statements (review before executing): SELECT 'DROP INDEX CONCURRENTLY ' || indexrelname || ';' AS drop_statement, relname AS table, pg_size_pretty(pg_relation_size(indexrelid)) AS size FROM pg_stat_user_indexes JOIN pg_index USING (indexrelid) WHERE idx_scan = 0 AND NOT indisprimary AND NOT indisunique ORDER BY pg_relation_size(indexrelid) DESC; Only run on production after at least 2 weeks of stats accumulation.
▸
Warning
Bloat
Moderate table bloat (12.5% dead tuple ratio)
Autovacuum may be falling behind on high-write tables.
What to do
Run VACUUM ANALYZE. If this persists, lower autovacuum_vacuum_scale_factor (default 0.2 = 20% dead tuples before trigger — try 0.05 for busy tables).
▸
Warning
Vacuum
2 tables flagged for vacuum
2 tables have a dead tuple ratio above 10% with live rows present.
What to do
Run: VACUUM ANALYZE; To target specific tables: SELECT relname, n_dead_tup, n_live_tup, round(n_dead_tup::numeric/nullif(n_live_tup+n_dead_tup,0)*100,1) AS dead_pct FROM pg_stat_user_tables WHERE n_dead_tup > n_live_tup * 0.1 AND n_live_tup > 0 ORDER BY dead_pct DESC;
N+1 queries 3
Queries executing more than twice per request on average.
▸
Critical
orders#index
~24.7 calls/request
(max 50, sampled 312 requests)
Introduced in deploy
c4e8a56
— Bump pg gem to 1.6.0
(1d ago)
Query pattern
SELECT "line_items".* FROM "line_items" WHERE "line_items"."order_id" = $1
Example SQL
SELECT "line_items".* FROM "line_items" WHERE "line_items"."order_id" = 4821
What to do
This query runs ~24.7x per request in orders#index. This looks like an N+1 — loading line_items rows one at a time. In your controller or model, add eager loading: # Before (N+1): @records = Parent.all # each record.line_item triggers a query # After (eager loaded): @records = Parent.includes(:line_item)
▸
Critical
orders#index
~24.7 calls/request
(max 50, sampled 312 requests)
Introduced in deploy
c4e8a56
— Bump pg gem to 1.6.0
(1d ago)
Query pattern
SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2
Example SQL
SELECT "users".* FROM "users" WHERE "users"."id" = 917 LIMIT 1
What to do
This query runs ~24.7x per request in orders#index. This looks like an N+1 — loading users rows one at a time. In your controller or model, add eager loading: # Before (N+1): @records = Parent.all # each record.user triggers a query # After (eager loaded): @records = Parent.includes(:user)
▸
Warning
products#show
~8.3 calls/request
(max 22, sampled 189 requests)
Introduced in deploy
b7d9f12
— Add eager loading to orders#index
(2d ago)
Query pattern
SELECT "product_variants".* FROM "product_variants" WHERE "product_variants"."product_id" = $1
Example SQL
SELECT "product_variants".* FROM "product_variants" WHERE "product_variants"."product_id" = 156
What to do
This query runs ~8.3x per request in products#show. This looks like an N+1 — loading product_variants rows one at a time. In your controller or model, add eager loading: # Before (N+1): @records = Parent.all # each record.product_variant triggers a query # After (eager loaded): @records = Parent.includes(:product_variant)
Latest snapshot
Buffer hit ratio
99.20%
Index hit ratio
98.80%
Unused indexes
6 (48.0 MB)
Bloat ratio
12.5%
Long-running queries
0
Dead tuples
185,000
Connections
18 / 100
Snapshot taken
5m ago
Git commit
a3f8c21 — Fix order total calculation for discountsRecent deploys
a3f8c21
c4e8a56
b7d9f12
Like what you see?
Start free — no credit cardFree tier: 1 database, 3-day history. Upgrade anytime.