fedorthinks

Express course · No. 06

Languages and frameworks come and go. The data you store, and the shape you store it in, can outlive all of them — so choosing a database is choosing how your system remembers, and how hard it is to change its mind.

20 concepts · a diagram for each · cheat sheet at the end

§ 01

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.

Relational (SQL)Relational modelSQLTransactionsNoSQL familyDocumentKey-valueWide-columnGraphSpecialisedTime-seriesSearch engineVector DBObject storageGuaranteesACIDBASECAPScalingIndexReplicationShardingNormalisationChoosingPolyglot persistencePostgres first
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.

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

§ 02

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.

customersidnameemail1Annann@mail.com2Bobbob@mail.comordersidcustomer_idtotal10140.0011115.5012299.00foreign keyschema = fixed columns, checked on the way inorders point back to the customer they belong to
Two tables: an order holds customer_id — a foreign key pointing at its customer.
StoreRelational 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.

you write WHATSELECT title, yearFROM books JOIN authorsWHERE country = 'FR' AND year > 1950ORDER BY yearQuery plannerdecides HOWResultrowsuse indexjoin tablessort by yearthe plan is thedatabase's job
You write WHAT you want; the database's planner decides HOW to fetch it.
LanguageSQL· 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.

BEGINone transaction = one intentA − 100debitB + 100creditCOMMITboth savedROLLBACKneither saved✗ never: A − 100 saved, B + 100 lost
A transfer: debit and credit are one transaction. Either both COMMIT or both ROLLBACK.
ConceptTransaction· 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.

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

§ 03

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.

collection: productsdocument 1{ "id": 1, "name": "Mug", "price": 12, "tags": ["kitchen"] }document 2{ "id": 2, "name": "T-shirt", "sizes": ["S", "M", "L"], "color": "blue" }different fields, same collection — no central templateone read returns the whole object
Two products in one collection with different fields; the whole product comes back in one read.
StoreDocument 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.

GET session:42by known keykey → valuesession:42{ user: 7, cart: 3 }rate:ip:1.2.3.417cache:home<html>…</html>instant, no search✗ no rich queries: “all sessions where cart > 2”
Know the key, get the value instantly. Asking by the values is not possible.
StoreKey-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.

app 1writesapp 2writesapp 3writeshash(key)partition keyNode 1user:7 → t1 · t2 · t3 · t4 · …Node 2user:10 → t1 · t2 · t3 · t4 · …Node 3user:13 → t1 · t2 · t3 · t4 · …Node 4user:16 → t1 · t2 · t3 · t4 · …writes spread across many machines · wide rows · no joins
The partition key spreads writes across many machines; rows are wide, there are no joins.
StoreWide-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.

FRIENDFRIENDFRIENDWORKS_WITHLIKESAnnBobDanCaraJazz clubplace“friends of friends who like X” = follow the edges, no joins
“Friends of friends who like X”: just walk the edges Ann → Bob → Cara → Jazz club.
StoreGraph 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.

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

§ 04

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).

expired(retention)WHERE time BETWEEN t1 AND t2t1t2time →readings arrive in time order and are asked about by time
Points arrive in time order; a query is a window from t1 to t2; old data expires by retention.
StoreTime-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.

Postgressource of truthSearch indexElasticsearch“runing shoe”typo + stemmingsyncqueryinverted indexrun → doc 3, doc 7shoe → doc 7, doc 9red → doc 3ranked results1. doc 7 · 0.922. doc 3 · 0.613. doc 9 · 0.40a fast lens onto the data — not the source of truth
Data is copied from Postgres into a search index; a query with a typo returns a ranked list.
StoreSearch 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.

“refund policy”query textEmbedding modeltext → numbers[0.12, −0.83, …]vectorrefunds FAQreturnsmoney backpricingcareersoffice mapAPI docsnearest neighbours = closest in meaning
Text becomes a vector; the nearest points are the texts closest in meaning.
StoreVector 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.

photos (Postgres)iduser_ids3_key17photos/7/a1.jpg29videos/9/b2.mp4S3 bucketphotos/7/a1.jpg4.2 MB · imagevideos/9/b2.mp4310 MB · videobackups/db.tar12 GB · backuprecords in the DBpayloads in the bucket
The Postgres row holds only the key; the file itself lives in an S3 bucket.
StoreObject 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.

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

§ 05

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.

AAtomicityall or nothingCConsistencyrules always holdIIsolationno cross-talkDDurabilitysurvives a crashthe strict promise — for money, orders, inventory
The four letters of ACID and what each one promises.
GuaranteeACID· 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.

copies briefly disagreeNode Alikes 10likes 11Node Blikes 10likes 11Node Clikes 10likes 11Convergedeventuallyfast and available now, consistent a moment later
The write lands on node A at once, on B and C a little later. A moment of disagreement, then everyone agrees.
GuaranteeBASE· 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.

Node 1has dataNode 2has data✗partitionthe network split — pick one:CP — Consistencyrefuse writes, stay correctAP — Availabilitykeep serving, may divergecost: downtimecost: stale or conflicting data
The network broke: either CP (refuse, but stay correct) or AP (keep working, but may diverge).
TheoremCAP 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.

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

§ 06

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).

WITHOUT INDEXreadallWITH INDEXann@…bob@…cara@…dan@…eve@…sorted lookuptable rowsfast reads · but costs space and slows every write
Without an index the database reads every row; with one it jumps through a sorted list straight to the right row.
TechniqueIndex· 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.

AppwritesLeaderall writesFollower 1serves readsFollower 2serves readsFollower 3serves readscopylag: a moment behindleader dies → a follower takes oversame data, many machines: survive failure, spread reads
The leader takes writes and ships copies; followers serve reads and take over if the leader falls.
TechniqueReplication· 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.

AppRoutershard key: nameShard 1users A–MShard 2users N–Z“Ann”“Zoe”different data on eachbad key → hotspots, or queries that hit every shard
The router reads the key: “Ann” goes to shard 1, “Zoe” to shard 2. Each shard holds different data.
TechniqueSharding· 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.)

NORMALISEDorder 10order 11order 12address #51 Main StDENORMALISEDorder 10 · 1 Main Storder 11 · 1 Main Storder 12 · 1 Main Steach fact in one place · needs joinsfast reads · copies to keep honest
Left: every order points at one address. Right: the address is copied into each order.
TechniqueNormalization / 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.

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

§ 07

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.

Your appPostgressource of truthRediscache · sessionsSearchsearch barVector DBAI featuresS3filesdashed = fast copies kept in sync from the source of truth
Five stores, each for its own job. The truth lives in Postgres; the rest are copies.
PatternPolyglot 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.

Postgresone store to runRelationaltables + SQLJSONBdocumentsFull-text searchtsvectorpgvectorembeddingsJob queueSKIP LOCKED+ Redis, Elastic…only on measured painstart here · add a store only when a real pain demands it
One Postgres covers tables, documents, search, vectors, and a queue. A new store only on real pain.
PracticePostgres 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.

Search enginesynced copyVector DBsynced copyObject storagefiles by keyIndexspeeds readsRelational DBsource of truth · ACIDScale-outreplicas · shardsNoSQL familydoc · KV · wide · graphBASEeventually consistentCAPC or A on a splitfeedsfeedsrows point togrowsforcesoftenopposite of ACID
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 DatabaseRDBMS

Tables with a fixed schema, linked by foreign keys. The default.

SQLquery language

Describe what you want; the database decides how to fetch it.

Transactionall or nothing

Several writes as one unit: COMMIT all or ROLLBACK all.

The NoSQL family

Document Storedocument database

Flexible JSON documents; a thing is read whole.

Key-Value Storekey → value

Key → value, instantly. Cache, sessions, counters.

Wide-Column Storecolumn-family

Data across many machines to absorb a write firehose.

Graph Databasegraph store

Nodes and edges; relationship queries without painful JOINs.

Specialised stores

Time-Series DatabaseTSDB

Readings by time; queries by window, old data expires.

Search Enginefull-text search

Full-text search with ranking and typo tolerance. A copy, not the truth.

Vector Databasevector store

Embeddings and nearest-by-meaning search. The basis of RAG.

Object StorageS3

Big files by key in a bucket; the database keeps only a pointer.

Guarantees

ACIDthe strict promise

A transaction is wholly correct or didn't happen. For money.

BASEeventual consistency

Always available, copies converge eventually. For likes.

CAP Theorempick C or A

During a network split — either correctness or availability.

Scale

IndexB-tree index

A pointer for fast reads; the cost is space and slower writes.

Replicationleader–follower

The same data on many machines: reliability and reads. There is lag.

Shardinghorizontal partitioning

Different data on different machines by key. The key is near-permanent.

Normalization / Denormalizationone place vs copies

One fact in one place — or deliberate copies for speed.

Choosing

Polyglot Persistenceseveral stores

Each job its own store, one source of truth.

Postgres Firststart 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.