Core concepts · SQL versus NoSQL

Core concepts

SQL versus NoSQL

A decision you can say in under a minute: when a relational database is the design, and when a key-value, wide-column, document, or graph store earns its place.

2 min read system-design

“SQL versus NoSQL” is a bad question. The useful question is: what is the access pattern, and which invariants must the storage engine enforce?

Start here unless you have a reason

A relational database with real constraints is the right first drawing for most product systems. You get transactions, joins for the queries you did not predict, and a planner that uses indexes. Postgres in particular covers JSON when a slice of the row is schemaless, full text for a modest search, and even vectors. Reaching for a second database on minute ten is how designs become unexplainable.

You outgrow it for specific reasons, not for prestige:

  • Write throughput that cannot be handled by one primary even after you have removed unnecessary indexes and batched.
  • A data shape that is always fetched by one key and is enormous (events, time series).
  • A query the relational engine is bad at (nearest vectors at scale, heavy full-text with custom ranking, multi-hop graph traversals).

What the other families are for

Key-value (Redis, DynamoDB used as a key lookup): the key is the query. Excellent for caches, sessions, idempotency records, and “give me this id.” Poor the moment you filter on a non-key field.

Wide-column (Cassandra, Scylla, DynamoDB with composite keys): you design the table around one query. The partition key decides where the row lives and what is hot. You can scale writes. You cannot casually add a where-clause. Many query shapes means many tables.

Document: a hierarchy that is stored and fetched together (a menu, a product with variants). Good when the document is the unit of consistency. Bad when you need to query inside every document and then join across them.

Graph: relationships are the data, and queries are “friends of friends” or “what depends on this package” with a depth you do not know up front. A single join is not a graph problem.

Search and vector engines are indexes, not sources of truth. They are allowed to be rebuilt.

The invariant test

Ask one question before you leave Postgres: which updates must be atomic? Seat inventory and a payment auth. A task claim and a lease. An account debit and a ledger line. If those sit in one database, a transaction is a couple of statements. If they sit in two, you have a saga, compensation, and a new class of bugs. Sometimes that split is worth it. It should be a sentence you say on purpose.

Schema-on-read does not delete the schema. It moves the pain to every reader. For data you will query six months from now, a constraint at write time is cheaper than a cleanup job.

Further reading

Check yourself

Answer the questions. Multiple choice is scored on this device only.

1. Which requirement most strongly argues for a relational database?

2. You need 'orders by customer' and 'orders by restaurant' at huge write volume in a key-value store. What did you just sign up for?

3. Give the default and the exit ramp.