Postgres performance tuning for real workloads
Before you reach for a new database, exhaust Postgres. The indexing, query and configuration changes that bought us 10x headroom.
"We've outgrown Postgres" is one of the most expensive sentences in engineering — and it's usually wrong. Before migrating to something exotic, most teams have 10x of headroom sitting unused in their existing database. We almost always find it.
Find the slow queries first
Optimization without measurement is guessing. We start with pg_stat_statements to rank queries by total time, then read the query plans that matter.
- Indexes: the right composite or partial index turns a seq scan into a lookup.
- N+1 queries: often the real culprit lives in the application, not the DB.
- Connection pooling: a pooler like PgBouncer prevents connection storms.
Tune the config to the hardware
Default Postgres settings are deliberately conservative. Matching shared_buffers, work_mem and the planner cost settings to your actual hardware and workload often delivers a step change for free.
Databases are rarely the bottleneck people assume. Measure first, tune deliberately, and Postgres will carry you much further than you'd expect.
