Database Query Cache Strategy: Where to Put What
Caching is the second-largest performance lever after right-sized infrastructure. The patterns are well-known; mistakes are common.
Why cache
Caching is the second-largest performance lever after right-sized infrastructure. Wrong cache pattern delivers no benefit; worse, it ships stale data without warning.
- Latency win. Cache replaces a slow operation (DB query) with a fast one (memory lookup).
- Cost win. Cache hit avoids the DB CPU cycle; the database scales further per dollar.
- Wrong pattern. Cache without invalidation ships stale data; cache without TTL ships forever-stale data.
- Hit rate gates value. Below 70% hit rate the cache is mostly noise; tune key shape and TTL until the rate clears.
Four caching patterns
- Memoize, in-process; per-pod.
- Cache-aside, app reads cache; falls back to DB.
- Read-through, cache layer auto-populates from DB.
- Write-through, writes go to cache + DB.
Where to put cache
The placement decides the trade-offs. App-tier, database-tier, and CDN serve different latency and ownership profiles.
- App-tier (Redis). Low latency, shared across pods, max benefit; the default for in-house apps.
- Database-tier (PG buffer cache). Zero app changes, bounded by DB memory; the cheap optimisation.
- CDN. Only for HTTP-cacheable content; static assets, public API responses with cache headers.
- Per-pod memoisation. Sub-millisecond, no network; appropriate for small hot working sets that fit in process memory.
Cache stampede prevention
The most painful cache failure mode is the stampede. The cache expires, many requests hit the database simultaneously, the database collapses.
- Stampede. Cache key expires; N concurrent requests miss; all N hit the DB; DB falls over.
- Probabilistic early refresh. Some requests refresh the cache before expiry; the working set never goes fully cold.
- Single-flight. Only one request per key fetches from DB; the rest wait for that fetch to populate.
- Lock-on-miss. Distributed lock around the cache miss; deduplicates upstream calls across pods.
Antipatterns
- Cache without TTL. Stale forever.
- Cache invalidation by hand. Bugs.
- No stampede prevention. Single-cache-miss = DB outage.
What to do this week
Three moves. (1) Apply this pattern to your slowest production endpoint. (2) Measure p99 before/after. (3) Document the win and ship the runbook so the team can reproduce.