Why PostgreSQL
OLTP vs OLAP, ACID, history, when it's the wrong choice
PostgreSQL is a row-oriented, general-purpose database built for OLTP: lots of small, concurrent transactions that read and write individual rows safely. That's a different job than ClickHouse, which is built for OLAP — scanning and aggregating billions of rows at once. Knowing which category a workload falls into is the first design decision you make, before any schema or index.
OLTP vs OLAP
OLTP (Online Transaction Processing) means many short transactions
touching a handful of rows each — placing an order, updating a user's
profile, checking an inventory count. The access pattern is narrow and
deep: WHERE id = 42, update three columns, commit. OLAP (Online
Analytical Processing) means the opposite — few queries, but each one
scans millions or billions of rows to compute an aggregate. Postgres
is tuned for the first pattern: row-at-a-time storage, indexes for
fast point lookups, and a transaction model that lets thousands of
clients write concurrently without corrupting each other's data.
A brief history
Postgres traces back to the POSTGRES project at UC Berkeley in the 1980s, led by Michael Stonebraker as a successor to his earlier Ingres database. In the mid-90s it gained a SQL interface and was renamed PostgreSQL. Decades of continuous open-source development later, it's one of the most feature-complete relational databases that exists — full SQL, extensibility (custom types, functions, extensions), and a reputation for taking correctness seriously over cutting corners for speed.
ACID, briefly
Postgres is an ACID database:
- Atomicity — a transaction's changes all happen, or none do.
- Consistency — a transaction moves the database from one valid state to another, respecting constraints.
- Isolation — concurrent transactions don't see each other's uncommitted changes (with tunable strength — see Transactions & Isolation).
- Durability — once committed, a transaction's changes survive a crash (this is what the Write-Ahead Log exists for).
ACID is the whole point of choosing a relational database like Postgres over something eventually-consistent. If your application can tolerate stale or partial writes, you have more options; if it can't — payments, inventory, anything where "close enough" causes real damage — ACID guarantees are what you're paying for in engineering complexity.
When Postgres is the wrong choice
- Huge analytical scans. Aggregating billions of rows across a handful of columns is ClickHouse's job, not Postgres's — Postgres stores whole rows together on disk, so a query touching two columns out of fifty still reads all fifty.
- Pure key-value caching. If you need sub-millisecond lookups of ephemeral data with no durability requirement, Redis is a better fit — Postgres's durability and MVCC machinery is overhead you don't need.
- Unstructured document dumping ground. Postgres can store JSON (see JSON & Arrays), but if literally everything is schema-less documents with no relational structure, a document database may fit the access patterns better.
None of this means Postgres can't do some of these things — it can, often well enough — but knowing the shape it was designed for tells you when you're fighting the tool instead of using it.
This module starts with Docker & Setup — getting a real Postgres instance running locally before any of the internals below mean anything concrete.