Backend Performance Dec 10, 2024· 3 min read

Reducing P95 API Latency from 2.5s to 180ms with Redis & PostgreSQL Tuning

Shafikul Islam
Shafikul Islam

Backend Infrastructure & Cloud Performance Consultant

Reducing P95 API Latency from 2.5s to 180ms with Redis & PostgreSQL Tuning

Executive Summary & Background

API response times exceeding 2,000ms directly cause user churn, abandoned checkout carts, and customer dissatisfaction.

During an emergency backend performance audit for a high-traffic SaaS client, P95 API response times were reaching 2,500ms during peak business hours. Database CPU utilization on the primary PostgreSQL instance spiked above 88%, resulting in database connection timeouts and failed HTTP requests.

This case study breaks down how we diagnosed full table scans on a 15-million row table, fixed N+1 ORM query loops, implemented composite B-Tree indexing, deployed a Redis Cache-Aside layer, and configured PgBouncer connection pooling — dropping P95 API latency by 92.8% to 180ms.


Performance Benchmark Comparison

Benchmark MetricInitial Unoptimized BackendPost-Optimization BackendPerformance Improvement
P95 API Latency2,500ms (2.5 seconds)180ms92.8% Latency Drop
Primary DB CPU Usage88% (Near Collapse)18% (Idle Capacity)70% CPU Load Reduction
Max Throughput (RPS)120 Requests / sec1,450 Requests / sec12x Capacity Increase
Database Connection Failures45 errors / hour0 errors / hour100% Uptime & Stability

Root Cause Diagnostics

Using APM distributed tracing (OpenTelemetry) and PostgreSQL slow query logging (pg_stat_statements), we identified three severe bottlenecks:

  1. ▸
    Missing Composite Index on 15M Rows: The main dashboard query performed a full sequential scan across 15,000,000 records to filter by tenant_id and status while sorting by created_at. Each query took 1,250ms.
  2. ▸
    N+1 ORM Query Loop: The user list endpoint fetched 50 items in Query 1, then executed 50 individual SQL queries inside a loop to fetch nested user permissions.
  3. ▸
    Database Connection Overhead: Backend microservices spawned new TCP database connections on every incoming HTTP request, consuming 35% of PostgreSQL server RAM on idle process overhead.

Step-by-Step Engineering Remediation

Step 1: Composite B-Tree Indexing

We analyzed EXPLAIN ANALYZE execution plans and created targeted composite B-Tree indexes using non-blocking concurrent index creation:

-- 1. Identify slow queries in pg_stat_statements
SELECT query, calls, total_exec_time / calls AS avg_time_ms, rows
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 5;

-- 2. Create non-blocking composite index on tenant_id + status + created_at
CREATE INDEX CONCURRENTLY idx_orders_tenant_status_created
ON orders (tenant_id, status, created_at DESC);

-- 3. Verify index usage with EXPLAIN ANALYZE
EXPLAIN ANALYZE
SELECT id, total_amount, created_at
FROM orders
WHERE tenant_id = 'tenant_9821' AND status = 'COMPLETED'
ORDER BY created_at DESC
LIMIT 50;
-- Result: Replaced Sequential Scan (1,250ms) with Index Scan (3.2ms)!

Final Technical Outcomes

  • ▸
    P95 Latency: Reduced from 2,500ms to 180ms (92.8% decrease).
  • ▸
    Database CPU Load: Dropped from 88% to 18%, providing ample headroom for business growth.
  • ▸
    Cost Savings: Avoided a $4,000/mo database hardware upgrade by optimizing existing open-source software layer configuration.
Infrastructure Advisory

Scaling Infrastructure or Want to Cut Cloud Spend?

I help B2B SaaS platforms eliminate Kubernetes downtime, harden container security, and cut AWS compute bills by 30%+. Book a 20-minute diagnostic audit call.

Related Technical Articles