How a B2B SaaS Team Cut Postgres P99 Latency by 73% with Pooling, Replicas and Partitioning
An overloaded single Postgres instance was killing checkout latency. Connection pooling, read replicas, and time-based table partitioning brought P99 from 4.2 s to 1.1 s without a rewrite.
Data & Storage · intermediate · 12 min read · 2142 words · By Sandip Das · Published
Composite scenario: built from common industry patterns; the figures are illustrative.
What this covers
- The Situation
- The Problem
- Constraints
- Options Considered
- The Solution
- Implementation
- Results
- What Went Wrong Along the Way
- Lessons Learned
- Apply It Yourself
Key numbers
| Metric | Before | After |
|---|---|---|
| P99 API latency | 4.2 s | 1.1 s |
| Peak active Postgres connections | 178 | 22 |
| Connection errors per hour at peak | 1,600 | 0 |
| events date-range query P99 | 11.2 s | 0.4 s |
| dbt full run duration | 55 min | 19 min |
Key components
- PgBouncer (transaction mode) — Collapses hundreds of application-level connections into a small, stable pool of server connections, eliminating connection exhaustion.
- RDS Read Replicas — Offload read-heavy workloads and analytics queries from the primary, reducing its CPU and I/O pressure.
- Postgres Range Partitioning — Splits a 380 GB table into per-year partitions so the planner can prune irrelevant partitions and avoid full sequential scans.
- pg_stat_statements — Identifies the slowest queries by total execution time, giving the team a ranked list of what to optimise first.
- Prometheus + pgbouncer_exporter — Provides real-time visibility into pool saturation and replication lag, enabling proactive alerting before users are impacted.
The Situation
This is a composite scenario assembled from patterns the authors have observed across multiple production Postgres deployments; all organisation details and figures are illustrative.
The organisation is a 120-engineer B2B SaaS company that sells workflow-automation software to mid-market logistics firms. Their product is a Rails 7 monolith backed by a single Amazon RDS for PostgreSQL 15 instance (db.r6g.4xlarge, 16 vCPU, 128 GB RAM). The data team runs dbt models on the same instance during business hours. At peak the platform handles roughly 8,000 API requests per minute across 340 active tenants, with a 380 GB events table that grows by about 12 GB per month.
The engineering team is split into five product squads and one platform squad of four engineers. There is no dedicated DBA. The platform squad owns infrastructure, observability (Prometheus, Grafana, PagerDuty), and the Terraform code that manages AWS resources.
The rest of this case study — the trade-offs, the scaling numbers and the build prompt — is available to LearnXops members. Create an account or see membership.
Topics: postgres, database, connection-pooling, read-replicas, partitioning, scaling
Related case studies
- How a B2B SaaS Company Turned a Swampy S3 Data Lake into a Lakehouse with Apache Iceberg
- How a B2B SaaS Team Migrated 8 TB from Self-Managed MySQL to Aurora with Zero Downtime
- How Discord Migrated Trillions of Messages from Cassandra to ScyllaDB
- How Figma Scaled Postgres from One Overloaded Database to Vertical Partitioning and Horizontal Sharding
- The 2017 GitLab Database Deletion: When Five Backup Methods All Failed at Once
- The GitHub October 2018 Outage: How 43 Seconds of Network Partition Caused 24 Hours of Data Inconsistency