# A database is the system's memory

Express course on databases and data stores. 20 concepts — Relational, SQL, Transactions, Document, Key-value, Wide-column, Graph, Time-series, Search, Vector, Object storage, ACID, BASE, CAP, Index, Replication, Sharding, Normalization, Polyglot persistence — each with its English name, a diagram, and a card with an example and its cost. A one-page cheat sheet of every concept at the end.

- **Author:** Fedor Chishchin
- **Level:** intro
- **Reading time:** ~35 minute read
- **Published:** 2026-06-02
- **Source:** https://fedorthinks.com/learn/databases-express

---

## 1. What a database is for

A database is your system's long-term memory. Code gets rewritten; the data, and the shape you chose for it, tends to outlive everything around it.

### The data outlives the code

> A house gets repainted, refurnished, even re-roofed over decades — but the foundation poured on day one stays, because replacing it means lifting the whole house.

Languages change, frameworks get swapped, the UI is redrawn ten times. **The data and its structure usually stay**, because changing them on a live system full of real records is slow and risky. So the database is the first thing to think hard about, and the last thing to rush.

### A database answers two questions

> Choosing where to keep things asks two things: what shape are the things — books on shelves, or odd tools on pegs? — and how safe must they be — a vault, or a handy drawer?

Every store is defined by two things. First, its **data model**: how it shapes data — rigid tables, flexible documents, a graph of links. Second, its **guarantees**: strict correctness, or speed and availability with looser promises. Almost every database choice is a different answer to those two — and the rest of this course is the menu.

### Access pattern — pick by how you read and write

> A filing cabinet, a card catalogue, and a conveyor belt are all "storage" — but you choose by how you'll fetch things, not by which looks newest.

There is no best database. A store that's perfect for fast key lookups is wrong for deep relationship queries; one built for huge writes is wrong for strict bank transactions. The right question is your **access pattern**: what you read, what you write, how often, and how it must behave when things go wrong.

### The map: 20 concepts in six groups

> A metro map: first you see the whole lines, then you ride station by station.

The concepts in this course fall into six groups: the relational core, the NoSQL family, specialised stores, guarantees, scaling techniques, and how to combine it all.

_Diagram: Six groups of concepts — chapters 2–7 follow them._

Every concept below gets the same treatment: its **English name** (the term you'll search the docs for), a picture from life, a **diagram**, and a **card** with fields: _problem_, _idea_, _example_, _cost_, _when to use_, and _related_. A one-page cheat sheet waits at the end.

> **Before choosing a store:** "What shape is my data, how will I query it, and how strict must the guarantees be?"

> Code is easy to change. Data is not. Choose the store like a decision you'll live with for years — because you will.

## 2. The relational default

For most systems the default is the relational database — and it earns that default. Start here, and leave only with a reason.

### Relational Database — tables, rows, and relations

> A spreadsheet done right: each sheet is one kind of thing (customers, orders), each row one record, and orders point back to the customer they belong to.

This is the **relational database**. It stores data in **tables** with a fixed **schema**, and links tables by reference — an order row holds the id of its customer. That reference is called a **foreign key**. The schema is a promise about shape: every order has the columns it should, checked on the way in. **Structure up front, in exchange for sanity later.**

_Diagram: Two tables: an order holds customer_id — a foreign key pointing at its customer._

#### Relational Database (RDBMS)

- **Problem:** Data with structure and relationships that you'll ask many questions of.
- **Idea:** Tables with a fixed schema; tables linked through foreign keys.
- **Example:** Postgres, MySQL: tables `customers` and `orders`, each order has a `customer_id`.
- **Cost:** The schema needs thought up front; changing it on live data is work.
- **When to use:** **Almost always, as the starting point.** Leave only with a reason.
- **Related:** Speaks **SQL**, gives **Transactions** and **ACID**.

### SQL — ask for what you want, not how to get it

> You tell a librarian "every novel by French authors published after 1950, sorted by year" — and they work out how to find them. You describe the result, not the search.

**SQL (Structured Query Language)** is a **declarative query language**: you state the answer you want and the database plans how to fetch it, including joining tables together (**JOIN**). That plan is built by the **query planner**. `SELECT ... JOIN ... WHERE ...` can answer questions you never anticipated at design time — one of the relational model's quiet superpowers.

_Diagram: You write WHAT you want; the database's planner decides HOW to fetch it._

#### SQL (query language)

- **Problem:** You need to ask the data questions without hand-coding every search.
- **Idea:** Describe the result; the database picks the plan (indexes, joins, sorting).
- **Example:** `SELECT title FROM books JOIN authors ... WHERE country = 'FR' AND year > 1950 ORDER BY year`.
- **Cost:** Complex queries must be read carefully, and you check how the database actually runs them.
- **When to use:** Wherever there's a relational database — it's its native tongue.
- **Related:** The language of a **Relational Database**; made fast by an **Index**.

### Transactions — all or nothing

> A money transfer is two writes — minus here, plus there — but one intent. Either both happen or neither does; a half-done transfer is a disaster.

This is the **transaction**: a group of changes that either fully **commits** or fully **rolls back**, isolated from others, and survives a crash once confirmed. The set of those promises is called **ACID** (more in chapter 5). This is why banks, orders, and inventory live in SQL — **when correctness matters more than raw speed, you want this promise.**

_Diagram: A transfer: debit and credit are one transaction. Either both COMMIT or both ROLLBACK._

#### Transaction (all-or-nothing unit)

- **Problem:** One action is several writes; a crash in the middle leaves garbage.
- **Idea:** Wrap the writes in `BEGIN … COMMIT`: all of them are saved, or none.
- **Example:** A transfer: `A − 100` and `B + 100` in one transaction.
- **Cost:** Some speed, and harder scaling across machines.
- **When to use:** Money, orders, inventory — anywhere a wrong number is unacceptable.
- **Related:** The properties of a transaction are **ACID**.

### Why it's the right default

> A good general-purpose tool: not the fastest at any single job, but the one you reach for until a job specifically demands otherwise.

Structured data, real relationships, ad-hoc queries, strong guarantees — the relational database does all of it well, and modern Postgres also handles JSON, full-text search, and even vectors. **Begin every project here;** reach for something else only when a concrete pain — scale, shape, or access pattern — pushes you out.

> **The relational question:** "Does my data have clear structure and relationships I'll query in ways I can't fully predict yet?"

> Start with Postgres. The question isn't "why SQL" — it's whether you have a real reason not to.

## 3. When a table isn't the shape

Sometimes the rigid table is the wrong shape. "NoSQL" is really a family of stores, each bending the rules in a different direction for a different job.

### Document Store — a JSON document per thing

> A folder of filled-in forms, where each form can have slightly different fields — no central template forcing every one to match.

This is the **document store**. It keeps records as flexible **JSON-like documents**, nested and **schema-less**, so two records in one **collection** can differ. Great when shapes vary or evolve fast, and a whole thing — a product, a profile — lives as one document you fetch in a single read.

_Diagram: Two products in one collection with different fields; the whole product comes back in one read._

#### Document Store (document database)

- **Problem:** Record shapes differ or change fast; the table gets in the way.
- **Idea:** Each thing is one nested JSON document, with no shared rigid schema.
- **Example:** MongoDB: a product catalogue, user profiles.
- **Cost:** Fewer guarantees and harder cross-document queries than SQL.
- **When to use:** A thing is read whole, and different records have different fields.
- **Related:** Postgres does documents too (**JSONB**); often lives by **BASE** rules.

### Key-Value Store — a giant hash map

> A coat check — you hand over a ticket number, you get back exactly your coat. No searching, no questions, instant.

This is the **key-value store** — the simplest shape: a **key in, a value out**, blazingly fast. Perfect for caching, sessions, **rate-limit** counters, and anything you fetch by a known id.

_Diagram: Know the key, get the value instantly. Asking by the values is not possible._

#### Key-Value Store (key → value)

- **Problem:** You need data back very fast by a known id.
- **Idea:** Key → value, like a giant hash map.
- **Example:** Redis, DynamoDB: `session:42`, a page cache, a rate-limit counter.
- **Cost:** You can only look things up by key — no rich querying over the values.
- **When to use:** Cache, sessions, counters — anything where the id is known up front.
- **Related:** The typical "fast helper" next to the main database in **Polyglot persistence**.

### Wide-Column Store — built for enormous writes

> A vast warehouse with endless identical aisles, arranged so a thousand forklifts can stock shelves at once without bumping into each other.

This is the **wide-column store**. It spreads data across many machines by a **partition key** for **massive write throughput and scale**, trading rich queries and strict consistency for the ability to absorb a firehose. Powerful — and more operational work to run well.

_Diagram: The partition key spreads writes across many machines; rows are wide, there are no joins._

#### Wide-Column Store (column-family store)

- **Problem:** So many writes that a single SQL box would buckle.
- **Idea:** Spread data across many nodes by partition key; write in parallel.
- **Example:** Cassandra: event logs, telemetry, feeds at scale.
- **Cost:** No rich queries or strict consistency; harder to operate.
- **When to use:** A write firehose, with queries that are known up front and simple.
- **Related:** Essentially built-in **Sharding**; usually lives by **BASE**.

### Graph Database — when the links are the point

> A detective's pinboard — photos connected by string. The value isn't in any one photo; it's in the web of who's tied to whom.

This is the **graph database**. It models data as **nodes** and the **edges** between them, making relationship queries — "friends of friends who like this," "the path between these two accounts" — natural and fast, where SQL would need painful many-way joins. **Reach for it when the connections matter more than the records.**

_Diagram: “Friends of friends who like X”: just walk the edges Ann → Bob → Cara → Jazz club._

#### Graph Database (graph store)

- **Problem:** The main questions are about links, and in SQL they become many-storey JOINs.
- **Idea:** Nodes and edges are first-class data; a query walks the edges.
- **Example:** Neo4j: social graphs, recommendations, fraud detection.
- **Cost:** A narrow niche; awkward for ordinary records and reports.
- **When to use:** The connections matter more than the records.
- **Related:** An alternative to a **Relational Database** when JOINs become the pain.

> **The NoSQL question:** "Is the relational shape genuinely fighting me — varied documents, pure key lookups, a write firehose, or a web of relationships?"

> NoSQL isn't "newer SQL." Each store drops a guarantee to win something specific — know which one you're trading away.

## 4. Specialised stores

Beyond the general stores sit databases built for one job, where a purpose-built engine beats a general one by a mile.

### Time-Series Database — data stamped by the clock

> A heart-rate monitor's tape — an endless strip of readings, each tied to a moment, where you almost always ask "what happened between these two times?"

This is the **time-series database**. It's tuned for **data that arrives in time order and is queried by time** — metrics, sensor readings, prices. It ingests huge streams and answers "average per minute over the last week" fast, with built-in expiry of old data (**retention**).

_Diagram: Points arrive in time order; a query is a window from t1 to t2; old data expires by retention._

#### Time-Series Database (TSDB)

- **Problem:** A huge stream of readings, and every question is "what happened in this period".
- **Idea:** Store and index by time; aggregate windows fast.
- **Example:** InfluxDB, TimescaleDB: server metrics, sensors, prices.
- **Cost:** One more store to run; a poor fit for ordinary business data.
- **When to use:** Everything has a timestamp, and time is the main axis.
- **Related:** TimescaleDB is a Postgres extension — see **Postgres first**.

### Search Engine — full-text and relevance

> A search box that forgives typos, ranks the best matches first, and finds "running" when you typed "run" — like a librarian who knows what you meant.

This is the **search engine**. It builds an **inverted index** — "word → documents" — for **fast full-text search with ranking, fuzzy matching, and filters**: what a `LIKE '%word%'` in SQL does slowly and badly. It usually runs alongside your main database, kept in sync, powering the search bar and log exploration.

_Diagram: Data is copied from Postgres into a search index; a query with a typo returns a ranked list._

#### Search Engine (full-text search)

- **Problem:** `LIKE '%word%'` is slow, doesn't forgive typos, and doesn't rank.
- **Idea:** An inverted index of words, plus a relevance score.
- **Example:** Elasticsearch, OpenSearch: a site's search bar, log exploration.
- **Cost:** Must be kept in sync with the main database.
- **When to use:** Users search by text and expect "smart" search.
- **Related:** **Not the source of truth** — a fast lens onto it; part of **Polyglot persistence**.

### Vector Database — search by meaning

> Instead of matching exact words, you ask "find me things that feel like this one" — and it returns neighbours by similarity, not by keyword.

This is the **vector database**. It stores **embeddings** — numeric fingerprints of meaning — and finds the **nearest neighbours**, so you can search by similarity rather than exact text. This is the engine under **semantic search** and **RAG**, where an AI app retrieves the most relevant chunks to answer from.

_Diagram: Text becomes a vector; the nearest points are the texts closest in meaning._

#### Vector Database (vector store)

- **Problem:** You need things similar in meaning, but the words may not match.
- **Idea:** Store embeddings and search for the nearest neighbours.
- **Example:** pgvector, Pinecone: the query "refund policy" finds "returns" and "money back".
- **Cost:** Needs an embedding model, and syncing with the source data.
- **When to use:** Semantic search and RAG — the new essential store of the AI era.
- **Related:** pgvector is a Postgres extension; a copy of the data, like a **Search Engine**.

### Object Storage — where the big files go

> A self-storage unit — not for index cards, but for the furniture: bulky things you keep by label and haul out whole.

This is **object storage**. It isn't a database, but it's where the **large blobs** live — images, video, backups, documents — addressed by a **key** inside a **bucket** and served cheaply at scale. The pattern is almost universal: keep the file in object storage, keep a row pointing to it in your database. **Records in the DB, payloads in the bucket.**

_Diagram: The Postgres row holds only the key; the file itself lives in an S3 bucket._

#### Object Storage (S3, blob storage)

- **Problem:** Big files inside the database bloat it and are costly to serve.
- **Idea:** The file goes in a bucket by key; the database keeps only a row with that key.
- **Example:** S3 and its kin: photos, video, backups, documents.
- **Cost:** Not a database: no queries over contents, only "put/get by key".
- **When to use:** Any large file.
- **Related:** Shaped like a **Key-Value Store**, just for bulky things.

> **The specialised question:** "Is this a job — time, text, similarity, big files — where a purpose-built store crushes a general one?"

> Don't bend your main database into a search engine or a file server. Put the specialised job in the store built for it.

## 5. The guarantees

A database's deepest choice isn't its shape — it's what it promises when things go wrong. A little alphabet soup names that trade.

### ACID — pessimistic, correct, careful

> A bank teller who double-checks every entry and won't move on until the books balance — slower, but never wrong.

**ACID** is the **strict promise** relational databases make about transactions: every transaction leaves the data correct and complete, or doesn't happen at all. Four letters: **Atomicity** (all or nothing), **Consistency** (the data's rules always hold), **Isolation** (concurrent transactions don't interfere), **Durability** (what's confirmed survives a crash). **For money, orders, and anything where a wrong number is unacceptable, this is the trade you want.**

_Diagram: The four letters of ACID and what each one promises._

#### ACID (Atomicity, Consistency, Isolation, Durability)

- **Promise:** Every transaction is wholly correct, or didn't happen at all.
- **Example:** A bank transfer, placing an order, taking stock out of inventory.
- **Cost:** Some speed, and harder scaling across machines.
- **When to use:** A wrong number is unacceptable.
- **Related:** The properties of a **Transaction**; the opposite stance is **BASE**.

### BASE — optimistic, available, eventually right

> A busy shop that lets everyone keep buying even while the price tags are being updated — the numbers catch up in a moment, and that's fine.

Many NoSQL systems take the opposite stance: **BASE** (Basically Available, Soft state, Eventually consistent). They stay **fast and available** and accept that copies of the data may briefly disagree before converging. This is called **eventual consistency**.

_Diagram: The write lands on node A at once, on B and C a little later. A moment of disagreement, then everyone agrees._

#### BASE (Basically Available, Soft state, Eventually consistent)

- **Promise:** The system always answers; copies converge "eventually".
- **Example:** A like count, a feed, a view counter.
- **Cost:** You may briefly see a stale value.
- **When to use:** Availability beats instant precision, and a second of staleness costs nothing.
- **Related:** The opposite of **ACID**; the "A" choice in **CAP**.

### CAP Theorem — choose when the network breaks

> A team split by a downed phone line: each half can keep working alone (but they'll diverge), or down tools until reconnected (but you stop). You can't have both.

The **CAP theorem** says that when a **network partition** splits your database's machines, you must choose **Consistency** (refuse writes, stay correct) or **Availability** (keep serving, risk disagreement) — you can't have both during the split. Every distributed database makes this call. **Knowing which your store picks tells you how it behaves on its worst day.**

_Diagram: The network broke: either CP (refuse, but stay correct) or AP (keep working, but may diverge)._

#### CAP Theorem (Consistency, Availability, Partition tolerance)

- **Says:** During a network split you can't be both correct and available.
- **Example:** Two nodes lose contact: refuse the write (CP), or accept it on both and reconcile later (AP).
- **Cost:** CP — downtime; AP — stale or conflicting data.
- **When to think:** As soon as your data lives on more than one machine.
- **Related:** Raised by **Replication** and **Sharding**; the AP side is **BASE**.

> **The guarantees question:** "When two copies might disagree, do I need correctness even if it means downtime — or uptime even if it means staleness?"

> ACID for money, BASE for likes. The guarantee you need is set by the cost of being briefly wrong.

## 6. Fast and reliable at scale

A handful of techniques turn a database from a single fragile box into something fast and survivable. You'll meet all of them.

### Index — the book's index, for data

> To find a word in a 900-page book, you don't read every page — you flip to the index at the back and jump straight there.

An **index** is a side structure that turns a **full table scan** into a direct lookup — the **single biggest lever on read speed.** The catch: each index costs storage and slows writes (every insert has to update it too).

_Diagram: Without an index the database reads every row; with one it jumps through a sorted list straight to the right row._

#### Index (B-tree index)

- **Problem:** A query reads the whole table, and gets slower as the data grows.
- **Idea:** A sorted side structure on a column → a direct lookup of the row.
- **Example:** An index on `email`: find a user without scanning the whole table.
- **Cost:** Disk space, and every write gets slower.
- **When to use:** On the columns you actually filter and sort by — not every column, just in case.
- **Related:** Speeds up **SQL**; a search engine is a special index over text.

### Replication — keep copies, survive failure

> A document kept in three safes in three buildings — if one burns down, the others still hold it, and three people can read at once.

**Replication** keeps **copies of the data on several machines**. All writes go to the **leader**, and the **followers (replicas)** receive a copy and serve reads. If the leader dies, a follower takes over (**failover**). The catch is **replication lag**: a follower can be a moment behind, so a value you just wrote might not show up on a replica yet.

_Diagram: The leader takes writes and ships copies; followers serve reads and take over if the leader falls._

#### Replication (leader–follower)

- **Problem:** One machine is one point of failure and one ceiling on reads.
- **Idea:** The same data on several machines: the leader writes, followers read.
- **Example:** Postgres with two read replicas; if the leader falls, a replica becomes leader.
- **Cost:** Lag: a fresh write may not have reached the replica yet.
- **When to use:** You need reliability, or more reads than one machine can serve.
- **Related:** Copies **the same** data; **Sharding** splits **different** data. Both lead to **CAP**.

### Sharding — split when one box isn't enough

> One overflowing filing cabinet becomes A–M in one cabinet and N–Z in another. More room — but now you must know which cabinet a name lives in.

When the data or write load outgrows a single machine, **sharding** **splits the data across many** — users A–M here, N–Z there. Each part is a **shard**, and the field you split by is the **shard key**. It unlocks near-unlimited scale, but the **shard key is a hard, near-permanent choice:** pick badly and you get **hotspots**, or queries that have to hit every shard.

_Diagram: The router reads the key: “Ann” goes to shard 1, “Zoe” to shard 2. Each shard holds different data._

#### Sharding (horizontal partitioning)

- **Problem:** The data or the write stream doesn't fit on one machine.
- **Idea:** Split the data by a key across many machines.
- **Example:** Users A–M on shard 1, N–Z on shard 2.
- **Cost:** The key is near-permanent; a bad key → hotspots, or queries across every shard.
- **When to use:** Last: after indexes and replicas.
- **Related:** Built into a **Wide-Column Store**; together with **Replication** it leads to **CAP**.

### Normalization / Denormalization — one fact in one place, or copies for speed

> One master address list everyone refers to (no contradictions) versus stapling a copy of the address onto every order (faster to read, but now there are copies to keep honest).

**Normalization** keeps each fact in exactly one place — clean, no contradictions, the relational default. **Denormalization** deliberately duplicates data so reads are faster and need fewer joins. Both are valid; the rule is to do it **consciously**, and to always know which copy is the **source of truth** and which is just a fast duplicate. (Same lesson as a cache.)

_Diagram: Left: every order points at one address. Right: the address is copied into each order._

#### Normalization / Denormalization (one place vs fast copies)

- **Problem:** The same fact in several places drifts apart; but joins slow reads down.
- **Idea:** Normalize by default; denormalize on purpose where reads matter more.
- **Example:** An address in one `addresses` table vs a copy of it in every order.
- **Cost:** Normalization — more JOINs; denormalization — copies that must be kept in sync.
- **When to use:** Denormalize when measurably slow reads demand it.
- **Related:** The same "source of truth + fast copies" idea as **Polyglot persistence**.

> **The scale question:** "Is my real problem read speed (index, replicas), survival (replication), or sheer size (sharding) — and am I solving the one I actually have?"

> Add an index before a server, a replica before a shard. The cheapest scaling is the kind you don't have to operate.

## 7. Choosing well

You don't pick one database and force everything into it. Real systems use a few, each for the job it's best at.

### Polyglot Persistence — several stores, on purpose

> A kitchen has a fridge, a freezer, and a pantry — not one box forced to do all three. Each keeps what suits it.

This is the **polyglot persistence** pattern. Mature systems usually use several stores: Postgres as the source of truth, Redis for caching and sessions, a search index for the search bar, maybe a vector store for AI features and object storage for files. Each store does what it's good at. The discipline is keeping clear **which one holds the truth**, with the others as fast copies kept in sync.

_Diagram: Five stores, each for its own job. The truth lives in Postgres; the rest are copies._

#### Polyglot Persistence (several stores in one system)

- **Problem:** No single database can be the best at everything.
- **Idea:** Each job gets its own store; one explicit source of truth.
- **Example:** Postgres + Redis + a search index + a vector store + S3.
- **Cost:** Every store must be run, backed up, and kept consistent.
- **When to use:** When a real pain demands another store — not "just in case".
- **Related:** Starts from **Postgres first**; ties together almost every store in the course.

### Postgres First — start with Postgres, grow out of it deliberately

> A Swiss Army knife handles a startling amount before you ever need the full toolbox.

This is the **Postgres first** practice. Modern Postgres is astonishingly capable — relational core, JSON documents, full-text search, vectors, even a workable job queue. **Most products should start with just Postgres** and add a specialised store only when a real, measured pain demands it. Every extra database is another thing to run, back up, and keep consistent. The cheapest store is the one you didn't add.

_Diagram: One Postgres covers tables, documents, search, vectors, and a queue. A new store only on real pain._

#### Postgres First (start with Postgres)

- **Problem:** Teams add databases before the pain shows up.
- **Idea:** One Postgres, until a measured problem demands more.
- **Example:** JSONB instead of a separate document store, pgvector instead of a separate vector database.
- **Cost:** At very large scale a specialised engine will still win.
- **When to use:** At the start of almost any product.
- **Related:** The first step towards **Polyglot persistence** — once "for now" has ended.

### How it all connects

> A neighbourhood map after a long walk: now you see which streets lead where.

The concepts in this course don't live alone. The relational database is the **source of truth** with **ACID** guarantees; an **index** speeds up its reads; the search engine and the vector database are **copies** fed from it; object storage holds the files its rows point to. When one machine isn't enough, **replication and sharding** arrive — and with them the **CAP** choice. The NoSQL family often picks **BASE** — the opposite of ACID.

_Diagram: The main links between the course's concepts: the source of truth sits in the middle._

#### Before choosing a database

- **What shape is the data** — tables, documents, key-value, a graph?
- **How will I query it** — by id, by relationships, by text, by similarity, by time?
- **What guarantees do I need** — strict ACID, or is eventually consistent fine?
- **What's the read/write balance** and the rough scale?
- **Could Postgres already do this** before I add another store?
- **Which store holds the source of truth**, and which are just copies?

#### Smell tests that you chose wrong

- You're running `LIKE '%...%'` for search instead of a search engine.
- A **key-value store** where you constantly need to query by the values.
- **Five databases** for a product two people maintain.
- You picked **MongoDB to avoid schemas**, then rebuilt validation by hand anyway.
- **No clear source of truth** — two stores both claim to be authoritative.

#### Signs you chose well

- The **query you run most** is the one the store is fastest at.
- The **guarantee matches the stakes** — strict for money, relaxed for likes.
- You can name the **source of truth** for every important fact.
- You added each store to solve a **real, felt pain**, not a hypothetical.
- You could **explain the data model** to a new engineer in a few minutes.

## Cheat sheet: all 20 concepts

### The relational core

- **Relational Database** (RDBMS): Tables with a fixed schema, linked by foreign keys. The default.
- **SQL** (query language): Describe what you want; the database decides how to fetch it.
- **Transaction** (all or nothing): Several writes as one unit: COMMIT all or ROLLBACK all.

### The NoSQL family

- **Document Store** (document database): Flexible JSON documents; a thing is read whole.
- **Key-Value Store** (key → value): Key → value, instantly. Cache, sessions, counters.
- **Wide-Column Store** (column-family): Data across many machines to absorb a write firehose.
- **Graph Database** (graph store): Nodes and edges; relationship queries without painful JOINs.

### Specialised stores

- **Time-Series Database** (TSDB): Readings by time; queries by window, old data expires.
- **Search Engine** (full-text search): Full-text search with ranking and typo tolerance. A copy, not the truth.
- **Vector Database** (vector store): Embeddings and nearest-by-meaning search. The basis of RAG.
- **Object Storage** (S3): Big files by key in a bucket; the database keeps only a pointer.

### Guarantees

- **ACID** (the strict promise): A transaction is wholly correct or didn't happen. For money.
- **BASE** (eventual consistency): Always available, copies converge eventually. For likes.
- **CAP Theorem** (pick C or A): During a network split — either correctness or availability.

### Scale

- **Index** (B-tree index): A pointer for fast reads; the cost is space and slower writes.
- **Replication** (leader–follower): The same data on many machines: reliability and reads. There is lag.
- **Sharding** (horizontal partitioning): Different data on different machines by key. The key is near-permanent.
- **Normalization / Denormalization** (one place vs copies): One fact in one place — or deliberate copies for speed.

### Choosing

- **Polyglot Persistence** (several stores): Each job its own store, one source of truth.
- **Postgres First** (start with Postgres): One Postgres, until a real pain demands more.

> The best database decision is usually "Postgres, for now" — plus the wisdom to know exactly when "for now" has ended.

End of express course · 7 chapters · 20 concepts

Next comes depth: _Designing Data-Intensive Applications_ by Martin Kleppmann is the one book to read, alongside the Postgres docs and your store's own manual. But before the deep end — picture how your data will be read, written, and trusted. The database is where your system remembers; choose how it remembers before you choose what it's built with.
