Caching and Performance Engineering · Performance and Scalability

Database Performance

Indexes, query plans, N+1 queries and connection pooling.

Create a free account to save this page, take notes and track your progress. Sign in

Most backend latency is database time. Read query plans (EXPLAIN ANALYZE), add indexes that match filters and sort order (composite, covering, partial), eliminate N+1 patterns with joins or batched IN queries, fetch only needed columns, use keyset pagination, keep transactions short, and size connection pools (plus PgBouncer/ProxySQL) to what the database can handle. Move heavy analytics to replicas or warehouses.

EXPLAIN (ANALYZE, BUFFERS)
SELECT id, total_cents FROM orders
WHERE customer_id = 42 AND status = 'paid'
ORDER BY created_at DESC LIMIT 20;
-- Seq Scan on orders (actual time=0.03..812.4 rows=20) Filter rows removed: 2,400,000   ← problem

CREATE INDEX CONCURRENTLY idx_orders_customer_status_created
  ON orders (customer_id, status, created_at DESC) INCLUDE (total_cents);
-- Index Only Scan ... (actual time=0.05..0.21 rows=20)                                  ← fixed

Common pitfalls

  • Indexes on every column (slower writes, unused indexes).
  • ORM lazy loading in loops.
  • More app instances × pool size than the database allows.

Key points

  • EXPLAIN ANALYZE before and after
  • Composite/covering indexes match queries
  • Fix N+1, bound pools

Further reading: PostgreSQL: Using EXPLAIN

Practice questions

Why does column order matter in a composite index?

Answer

B-tree indexes are sorted by the first column, then the next; queries can use the index efficiently only for leftmost-prefix filters (and matching sort order).

How can adding app servers make database performance worse?

Answer

Each instance opens its own connection pool; too many connections exhaust database memory and cause contention. Use poolers and bound total connections.

Open in the app to mark lessons complete, take notes and track your progress.

Was this page helpful?