Skip to content
Back to Architecture Decisions

Database Selection

Match the database to the workload — OLTP, OLAP, KV, time-series, search — not to 'the one we know'.

Why

Using Postgres for everything works until it doesn't — a time-series workload on Postgres is 10x the cost of InfluxDB, a graph traversal on Postgres is 100x the latency of Neo4j, a KV lookup on Postgres is 5x the cost of Redis. Each database is optimized for a workload shape, and using the wrong one means you're fighting the database instead of using it. The right choice is driven by the access patterns (see data-modeling), not by 'we already have Postgres'. That said, operational reality matters: running 5 databases is expensive, so the art is covering your workloads with the minimum number of databases, accepting 'good enough' for the long tail.

When

When a new workload appears that doesn't fit existing stores. Takes half a day. Revisit if a store becomes a bottleneck.

How

1. Classify the workload:
   - OLTP (transactions, many small writes/reads) → Postgres/MySQL
   - OLAP (analytics, few big aggregations) → BigQuery/Snowflake/ClickHouse
   - KV (key → value, sub-ms) → Redis/DynamoDB
   - Time-series (timestamped, high-write) → InfluxDB/TimescaleDB
   - Search (full-text, faceted) → Elasticsearch/Meilisearch
   - Graph (relationships, traversals) → Neo4j/Neptune
2. Check if an existing store can serve it "well enough" (e.g. Postgres + ts extension for time-series)
3. If not, evaluate the new store: managed option? ops cost? migration path?
4. Compute TCO of adding vs forcing into existing (see tco-analysis)
5. Prefer the minimum number of stores that covers all workloads — each new store is ops overhead
6. Document the workload → store mapping in the architecture doc

Example

Workloads:
  1. user/order CRUD (OLTP) → Postgres (existing) ✓
  2. monthly revenue analytics (OLAP) → Postgres is slow at 100M rows
  3. real-time metrics (time-series) → Postgres bloats fast
  4. product search (full-text) → Postgres trigram is OK but not great

Options:
  A. Force all into Postgres: works, but #2 takes 40s, #3 bloats 500GB/mo
  B. Add ClickHouse (#2) + Redis (#3) + Meilisearch (#4): 3 new stores, $1.2k/mo
  C. Add ClickHouse (#2) + TimescaleDB (#3, Postgres ext) + Postgres trigram (#4)

Decision: C — 1 new store (ClickHouse), 1 extension, accepts "good enough" search.
  Covers all workloads, minimizes ops overhead.

Common Problems

  • ⚠Adding a new database for every workload — you end up with 7 databases and no team can operate them all; consolidate where 'good enough' works.

Best Practices

  • ✓Start with Postgres + Redis for most systems — they cover 80% of workloads well; add a specialized store only when one is clearly failing.
  • ✓Use Postgres extensions (TimescaleDB, PostGIS, pgvector) before adding a new database — you get the specialization without the ops overhead.

Related Resources