Notes
Relational
Relational. Tables with a fixed schema, linked by keys. What it makes cheap: joins, ad-hoc queries you didn't plan for, and transactions across many rows. PostgreSQL and MySQL. Use it for users, orders, payments, anything with relationships or money. It's the default; you need a reason to pick something else.
- data: tables with a schema
- cheap: joins, ad-hoc queries,
- multi-row transactions
- PostgreSQL, MySQL, SQL Server
- use for: users, orders,
- payments, anything with
- relationships and money
Key-value
Key-value. The simplest model: put a value under a key, get it back by that key. No queries on the value. In exchange, lookups are sub-millisecond and scale almost without limit. Redis in memory, DynamoDB on disk. Use it for sessions, caches, shopping carts, rate-limit counters, feature flags.
put(key, value) get(key) → value cheap: lookup by exact key, sub-millisecond, huge scale Redis (RAM), DynamoDB, etcd, Memcached use for: sessions, caches, carts, rate limits, config
Document
Document. Each record is a JSON-like tree: a product with its variants and specs nested inside. What's cheap: reading or writing the whole object in one go, and records that don't all share the same fields. MongoDB, Firestore. Use it for product catalogs, content, user profiles. What's expensive: joins across documents.
{ "id": 42, "name": "Lamp",
"variants": [ {...}, {...} ],
"specs": { ... } }
cheap: read/write a whole
nested object, flexible shape
MongoDB, Firestore, Couchbase
use for: catalogs, CMS, profiles Wide-column
Wide-column. Rows grouped by a partition key and sorted inside it: all messages for one chat, ordered by time. It sits on the LSM trees from last episode, so it swallows enormous write rates and makes 'latest fifty for this key' cheap. Cassandra, ScyllaDB, Bigtable. Discord stores trillions of messages this way. The catch: you design tables per query, up front.
partition key → sorted rows (user_id) → messages by time cheap: huge write rates, "latest N for this key" Cassandra, ScyllaDB, HBase, Bigtable use for: chat history, feeds, activity logs, IoT
Graph
Graph. Data as nodes and edges. What's cheap is following relationships: friends of friends who like this band, the shortest path between two accounts. In SQL each hop is another join and it gets slow fast; a graph database just follows pointers. Neo4j, Neptune. Use it for social graphs, fraud-ring detection, recommendations.
- data: nodes + edges
- cheap: traversals,
- "friends of friends who
- like X", shortest paths
- in SQL: one JOIN per hop;
- in a graph DB: follow pointers
- Neo4j, Amazon Neptune
- use for: social, fraud rings,
- recommendations
Time-series
Time-series. Every point is a value at a timestamp, with tags. Writes are append-only, and the cheap queries are averages and maxima over time windows, plus automatic downsampling and expiry of old data. Prometheus, TimescaleDB, InfluxDB. Use it for metrics, monitoring, sensor data, price ticks.
(metric, tags, time) → value cheap: append-only writes, avg/max over time windows, downsampling, expiry Prometheus, TimescaleDB, InfluxDB use for: metrics, monitoring, sensors, stock ticks
Search
Search. An inverted index maps every word to the documents containing it, so full-text queries, relevance ranking, typo tolerance and facet counts are cheap. Elasticsearch, OpenSearch. One important habit: it's almost always a secondary copy, fed from your main database, not the source of truth.
inverted index:
"red" → doc 3, 9, 41
"shoes" → doc 9, 41, 77
cheap: full-text search,
relevance ranking, typos,
facets ("size: 9 (124)")
Elasticsearch, OpenSearch
usually a copy, not the truth Polyglot
Real systems mix them. A shop keeps orders and users in PostgreSQL as the source of truth, sessions and carts in Redis, and product search in Elasticsearch, fed by change data capture from the main database. That's called polyglot persistence: each store does the one job it's built for.
- e-commerce example:
- PostgreSQL: orders, users
- (source of truth)
- Redis: sessions, cart, cache
- Elasticsearch: product search
- (fed by change data capture)
- each store does one job well
Decision
How to choose, in order. Start relational. Need sub-millisecond reads by key: add a key-value cache. A firehose of writes per key: wide-column. Deep relationship queries: graph. Metrics over time: time-series. Full-text: a search index. The trick in an interview is to name the query first, then the store that makes it cheap.
- 1. start relational
- 2. need sub-ms by key? + KV cache
- 3. firehose writes per key?
- wide-column
- 4. deep relationships? graph
- 5. metrics over time? time-series
- 6. full-text? search index
- name the query, then the store