SQL Database
A row-oriented, ACID-compliant relational database — the default for transactional workloads.
Why it exists
For the last 40 years, SQL databases have been the standard answer for storing structured data with strong consistency. When you need to atomically move money from one account to another, when you need referential integrity across tables, when you want ad-hoc queries with JOINs — you reach for SQL. It's the boring, dependable, well-understood choice, and most projects reach for NoSQL prematurely.
How it works
A SQL database organizes data into tables with typed columns and enforces constraints (primary keys, foreign keys, unique, NOT NULL). Modern engines use B-tree indexes for point/range queries and MVCC (multi-version concurrency control) so readers don't block writers. Transactions provide ACID guarantees. Under the hood: a page cache in RAM, WAL (write-ahead log) for durability, and a query planner that turns SQL into an execution plan.
Scaling characteristics
A well-tuned Postgres or MySQL primary handles ~10K QPS read and ~1K QPS write on a single m5.2xlarge. Read scaling: read replicas (async replication, ~ms lag). Write scaling: partition tables OR shard across multiple databases (application-level or via Vitess/Citus/Aurora). Storage: single-instance limit ~64 TB on managed services; sharded fleets scale to petabytes.
When to use it
- Transactional workloads (payments, inventory, bookings, anything with money)
- Relational data with well-known query patterns
- You need JOINs, ad-hoc queries, and reporting
- Team is familiar with SQL and standard tools
- You value correctness > raw throughput
When NOT to use it
- Massive write throughput (>50K writes/sec) without sharding investment
- Schemaless / rapidly-evolving data models (though Postgres JSONB narrows this gap)
- Time-series ingest at millions of events/sec (use a TSDB)
- Full-text search (use Elasticsearch, though pg_search exists)
Failure modes
- Primary DB down → automatic failover to a synchronous replica (~30s outage window)
- Replication lag → read replicas serve stale data; write-then-read from the same session fails
- Long-running transactions → lock contention → cascading queue depth
- Bad query without index → full table scan pegging CPU and blocking short queries
- Connection storm → 'too many connections' errors; mitigate with PgBouncer/ProxySQL
- MVCC bloat → table gets slow over time from dead-tuple accumulation; VACUUM must run
Alternatives
- NoSQL wide-column (Cassandra, DynamoDB) for horizontal write scale with weaker consistency
- Document store (MongoDB) for schemaless flexibility
- NewSQL (Spanner, CockroachDB, TiDB) — SQL API with horizontal scale + strong consistency, at a latency cost
- Time-series DB (InfluxDB, TimescaleDB) for append-heavy metric data
Interview questions
- You're at 10K writes/sec on a single Postgres primary. What breaks first?
- How would you shard by user_id, and what queries become hard?
- How do you handle a schema migration on a 100 GB table with zero downtime?
- What's the difference between REPEATABLE READ and SERIALIZABLE, and when does it matter?
- Read replica lag is 30 seconds. What now?
- You have a 2-column index on (a, b) — will a query on b alone use it? Why or why not?
Systems that use this component
See how the real designs on this platform put sql-db to work — concrete usage context per system.
URL Shortener
RDS Postgres Multi-AZ for URL storage; boring and correct
Open systemPayment System
Postgres with strict transactions for ledger; Multi-AZ synchronous replication
Open systemTicket Booking
Postgres for seat inventory with row-level locks
Open systemTwitter/X timeline
MySQL (historical) for user data; Manhattan for tweets at scale
Open systemPostgres for user metadata + photo references
Open systemSlack
MySQL for workspace metadata + user data
Open system1970, IBM San Jose: a paper changes how we store data forever
In 1970, IBM mathematician Edgar F. Codd published "A Relational Model of Data for Large Shared Data Banks." His argument was radical: data should live in tables of rows with mathematical relationships between them, not in the tangled navigational trees his colleagues at IBM had spent a decade building. Any query should be expressible as algebra over sets. IBM ignored him for 4 years.
Then in 1974, IBM's System R project proved Codd right. It introduced SQL (originally "SEQUEL") and demonstrated a working query optimizer. A young engineer named Larry Ellison read the papers, sensed the opportunity, and shipped Oracle v2 in 1979 — before IBM. Ellison's bet on Codd's ideas made him a billionaire.
For the next 25 years, the world ran on relational databases: DB2, Oracle, SQL Server, and then the open-source revolutionaries MySQL (1995) and PostgreSQL (1996). Then in ~2009 came the NoSQL rebellion — MongoDB, Cassandra, DynamoDB. "SQL is dead," declared the blogs. The rebellion lasted about 5 years. By 2015, everyone realized: if your data has relationships and you want money-adjacent correctness, you want ACID transactions. NoSQL added SQL-like layers. Distributed SQL was born (Spanner, CockroachDB, YugabyteDB). Today, SQL is winning again.
The core insight: SQL databases give you four guarantees you can bet a business on — ACID (atomicity, consistency, isolation, durability). If your account balance is stored in a SQL database and you follow the rules, you literally cannot lose or double-count money in a crash. That's not a marketing claim; it's a mathematical property enforced by mechanisms we'll unpack below: MVCC, WAL, isolation levels, and B-tree indexes.
Historical timeline
- 1970Codd's relational paperTed Codd publishes the relational model. Every SQL database traces back to this paper.
- 1974IBM System R + SQLIBM San Jose builds the first working relational DB. SEQUEL (later SQL) is born.
- 1979Oracle v2 ships (before IBM)Larry Ellison's startup RSI (later Oracle) releases the first commercial SQL DB — beating IBM to market by 2 years.
- 1983IBM DB2 launchesIBM commercializes what became DB2. Sets the standard for enterprise-grade SQL.
- 1986SQL standardized (ANSI SQL-86)First ANSI SQL standard. Codifies syntax across vendors — the reason SQL knowledge is portable to this day.
- 1989PostgreSQL project starts (Berkeley)Michael Stonebraker leads the "Postgres" project — the "post-Ingres" successor. Becomes PostgreSQL in 1996.
- 1995MySQL releasedMonty Widenius releases MySQL (named after his daughter, My). Free + fast + simple → default for early web.
- 1996PostgreSQL 6.0First release under the PostgreSQL name. MVCC-based. Sets the tone for correctness over speed.
- 2005SQLite reaches ubiquityD. Richard Hipp's embedded SQL DB gets built into every phone, browser, and app. Runs on more devices than any other DB.
- 2008Sun buys MySQL for $1BSun acquires MySQL AB. Peak of MySQL's influence. Oracle acquires Sun in 2010, triggering MariaDB fork.
- 2012Google Spanner paperGoogle publishes Spanner — the first globally-distributed, externally-consistent SQL DB. Uses atomic clocks (TrueTime). Rewrites what's possible.
- 2015CockroachDB launchesEx-Googlers Andy Kimball + Peter Mattis build open-source Spanner. Distributed SQL becomes a category.
- 2018AWS Aurora dominatesAmazon Aurora — cloud-native MySQL/Postgres — becomes AWS's fastest-growing service. Storage separated from compute changes economics.
- 2022PlanetScale + Neon serverless SQLServerless MySQL (PlanetScale on Vitess) and Postgres (Neon) reimagine dev experience — branch a DB like Git.
- 2024SQL wins the AI eraVector extensions (pgvector, DuckDB) mean SQL databases become the substrate for AI apps too. Postgres runs the world's embeddings.
Transaction lifecycle — the atomic promise
Every SQL transaction goes through this pipeline. Understanding it explains why crashes don't lose data and why concurrent transactions can co-exist without stepping on each other:
Phase 1: BEGIN
Transaction ID (XID) assigned. Snapshot taken (in MVCC). No changes visible to others yet.
The four SQL isolation levels — a trade-off ladder
Isolation is the "I" in ACID — and it's a spectrum, not a boolean. Higher isolation = fewer concurrency bugs but lower throughput. The ANSI standard defines four levels:
READ UNCOMMITTED
READ COMMITTED (Postgres/Oracle default)
REPEATABLE READ (MySQL InnoDB default)
SERIALIZABLE
Concurrency: MVCC vs Locking (why Postgres readers never block)
Two philosophies compete for handling concurrent transactions. The choice shapes latency, throughput, and even VACUUM behavior:
Locking (SQL Server, older MySQL)
Readers acquire shared locks. Writers acquire exclusive locks. Readers block writers and vice versa. Simple, deterministic.
# holds S-lock
T2: UPDATE users SET name='X' WHERE id=1
# WAITS for T1
MVCC (Postgres, Oracle, InnoDB)
Every write creates a new row version tagged with its XID. Readers see the version visible at their snapshot. Readers never block writers.
T2: UPDATE users SET name='X' WHERE id=1 # creates v2
T1: SELECT * FROM users WHERE id=1 # still sees v1
WAL: how a crash never loses committed data
Write-Ahead Log (WAL) is the invention that made durability practical. Rule: every change is logged to disk BEFORE the actual data page is updated in memory. On crash, replay the log. Try the simulator:
Eight index types — pick the right shape for your query
"Add an index" is the most common performance advice. The right index type matters as much as the columns you index. Postgres alone ships eight:
B-tree (default)
Hash
GIN (inverted)
GiST
BRIN
Covering (INCLUDE)
Bloom
Vector (IVF/HNSW)
Four replication topologies — how SQL scales beyond one machine
A single SQL server maxes out at ~10-50K writes/sec depending on workload. Beyond that, you need replication. Four topologies dominate:
Primary + async replicas
Client
↓
Primary → Replica 1 (read-only)
→ Replica 2 (read-only)Product comparison
| Database | Model | Strength | Weakness |
|---|---|---|---|
| PostgreSQL | OSS | Feature-richest OSS SQL. JSONB, full-text, extensions (PostGIS, pgvector, TimescaleDB) | MVCC bloat if VACUUM neglected. Single-writer scaling ceiling. |
| MySQL / MariaDB | OSS | Simple, fast, huge community. Battle-tested at web scale. | Less feature-rich than Postgres. Sub-tree of features are Oracle-controlled. |
| SQL Server | Commercial | Best-in-class tooling. Deep Windows/AD integration. Robust transactional workloads. | Expensive licenses. Linux support catching up but not first-class. |
| Oracle Database | Commercial | The enterprise standard. Unmatched performance tuning. RAC for HA. | Very expensive. Complex to operate. License audits are notorious. |
| SQLite | OSS (embedded) | Zero config. In-process. Runs on every phone. Correct + tiny. | Single writer. No network access. Not for concurrent server workloads. |
| Amazon Aurora | Managed | Cloud-native MySQL/Postgres. Storage/compute separated. 15 replicas, <100ms failover. | AWS lock-in. More expensive than raw RDS at low scale. |
| Google Cloud Spanner | Managed | First truly global, strongly-consistent SQL. TrueTime clocks. Powers Google Ads. | GCP-only. Expensive at low scale. Limited SQL subset historically (improving). |
| CockroachDB | OSS + Managed | Postgres-compatible distributed SQL. Multi-region OSS. | Higher latency than single-node PG. Complex to operate self-hosted. |
| YugabyteDB | OSS + Managed | Postgres compatible, distributed. Two APIs (SQL + Cassandra). Multi-region. | Younger community than Cockroach. Docs less mature. |
| PlanetScale (Vitess) | Managed | MySQL at YouTube scale. DB branches like Git. Zero-downtime schema changes. | MySQL-only. Managed-only after 2024. Foreign key gotchas in sharded mode. |
| Neon | Managed serverless | Serverless Postgres. Branch DBs like Git. Scale-to-zero cheap. | Cold start latency. Newer product. |
| TiDB | OSS + Managed | MySQL-compatible distributed SQL + HTAP (row + column store). | Complex operationally. Ecosystem outside China smaller. |
How to choose: Default for new project → PostgreSQL. AWS shop, want managed → Aurora Postgres. Need global writes → Spanner (if on GCP) or CockroachDB. Web-scale MySQL → PlanetScale. Embedded / edge → SQLite. Serverless dev workflow → Neon. Enterprise + Windows → SQL Server.
12 real-world SQL patterns
MongoDB → PostgreSQL migration for consistency
Stripe famously migrated key workloads from MongoDB to Postgres as their transaction volume grew. Reason: they needed strict serializable semantics for balance updates, refunds, disputes. MongoDB's consistency model was too weak for money. Today, Stripe runs on hundreds of Postgres clusters — most sharded by merchant ID.
MySQL at 4B searches/day
Airbnb runs on MySQL 8 — sharded, replicated, backed by Vitess for horizontal scale. Every booking, every search, every review passes through it. Migrated off huge Ruby-monolith DB to a set of service-owned databases. Vitess handles cross-shard queries. Reliability > feature-richness in their tech philosophy.
MySQL at 100M+ users
GitHub runs on MySQL + Vitess too. Every commit, PR, issue, review — all ACID. They open-sourced gh-ost, an online schema migration tool for MySQL. Handles schema changes at their scale without downtime. Runs vast fleets of replicas.
PostgreSQL scaled to billions
Instagram famously stayed on PostgreSQL even after Meta acquisition. Sharded early (by user ID hash). Every photo upload, like, comment: ACID transaction. They wrote extensive blog posts on Postgres tuning for their scale. Proves single-machine SQL can go further than most think.
Postgres → MySQL → Postgres, then own DB
Uber's famous "Why We Left Postgres" blog post (2016) caused a firestorm. They moved to MySQL, then partially back to Postgres, and eventually built Schemaless — a MySQL-backed KV layer with schema evolution. Lesson: no DB is one-size-fits-all at extreme scale.
Postgres partitioning: 200x table split
Notion's "blocks" table hit 200TB. They partitioned it across 480 shards using consistent hashing. Zero downtime migration described in their engineering blog. Every page-load = ~50 partition lookups. Postgres routes them. Proves you can shard Postgres if you invest.
Cassandra → ScyllaDB → PG for latest features
Discord runs messages on ScyllaDB (Cassandra-compatible) but keeps user profiles, servers, permissions in PostgreSQL. Hybrid: right DB for right shape. Postgres for entities with relationships; ScyllaDB for the high-cardinality message store.
Postgres + Cassandra hybrid
Reddit stores votes, comments, submissions in Postgres, and hot-page rendering data in Cassandra. Postgres gives them ACID for authoritative data. Cassandra gives them denormalized read paths. The pattern: SQL as system of record, NoSQL as fast-serving cache.
Postgres + Debezium CDC to Kafka
Robinhood uses Postgres as the source of truth for accounts + orders. Debezium streams every commit to Kafka via logical replication. Downstream services (fraud, analytics) consume the stream. This is the modern "SQL as event source" pattern.
PostgreSQL for control plane, KV for data
Cloudflare runs PostgreSQL for their control plane (accounts, DNS zone metadata, WAF rules). The edge (300+ PoPs) reads distributed KV. Any config change in PG propagates to the edge in seconds via change stream. ACID control + high-availability delivery.
Vertical PG → horizontal sharding
Figma ran on a single vertically-scaled Postgres until 2023 (r6i.32xl!). Then they sharded — described in "How Figma's databases team lived to tell the scale." Postgres-native logical replication for zero-downtime migration. Proves how far vertical PG can go.
Managed Postgres for money movement
Coinbase runs a huge fleet of Aurora PostgreSQL instances. Money movement requires strict ACID; Aurora gives them PG semantics + AWS-managed HA + 15 replicas. Every buy/sell/withdraw = ACID transaction. Aurora's 6-way replicated storage means zero data loss on AZ failure.
Key takeaways
- 1SQL databases give you ACID — the 4 guarantees your business logic depends on. Never trade this for perf unless you know exactly why.
- 2MVCC is why modern DBs feel non-blocking. Every write creates a version; readers see their own snapshot. Pay attention to VACUUM.
- 3Isolation levels are a ladder of correctness vs throughput. Default (READ COMMITTED / REPEATABLE READ) works for 90% of workloads. SERIALIZABLE for money.
- 4The WAL is what makes crashes safe. Every commit fsyncs the log before ack. Recovery replays it. Fast SSDs make this practical.
- 5Indexes beyond B-tree matter more than most engineers know. GIN for JSONB, BRIN for time-series, vector for AI, covering for hot read paths.
- 6Vertical Postgres scales further than you think — Figma ran on one r6i.32xl to $10B valuation. Only shard when you must.
- 7Managed cloud SQL (Aurora, Cloud SQL, Neon) removes 90% of operational pain. Unless you have a strong DBA, just use it.
- 8Distributed SQL (Spanner, CockroachDB, Yugabyte) is now viable for multi-region correctness. Comes with new latency profile — measure carefully.
References & further reading
- • Codd, E. F. (1970). "A Relational Model of Data for Large Shared Data Banks." CACM 13(6). The paper that started it all.
- • Chamberlin, D. & Boyce, R. (1974). "SEQUEL: A Structured English Query Language." IBM San Jose. The birth of SQL.
- • Gray, J. & Reuter, A. (1993). Transaction Processing: Concepts and Techniques. Morgan Kaufmann. The bible of transactional systems.
- • Berenson et al. (1995). "A Critique of ANSI SQL Isolation Levels." ACM SIGMOD. Explains why isolation levels are trickier than they seem.
- • Corbett, J. et al. (2012). "Spanner: Google's Globally Distributed Database." OSDI. The paper that redefined distributed SQL.
- • Kleppmann, M. (2017). Designing Data-Intensive Applications. O'Reilly. Modern SQL context, especially chapters 7 & 9.
- • PostgreSQL Docs: "Concurrency Control" chapter. The clearest explanation of MVCC anywhere.
- • Aurora Whitepaper (SIGMOD 2017): "Amazon Aurora: Design Considerations for High Throughput Cloud-Native Relational Databases."
- • Uber Engineering (2016): "Why We Left Postgres." The (in)famous post. Read alongside the many rebuttals.
- • Instagram Engineering: "Sharding & IDs at Instagram." How they scaled Postgres to billions.
- • Figma Engineering (2023): "How Figma's databases team lived to tell the scale." Real-world migration to sharded PG.