Data & Databases

Lesson 1 of 7

SQL vs NoSQL

"The choice of data model is the most important decision you will make when designing a system." — Martin Kleppmann, Designing Data-Intensive Applications

Almost every system design starts with the same fork in the road, and interviewers know it: where does the data live, and in what shape? Get this right and joins, transactions, and scale fall into place naturally. Get it wrong and you spend the next two years bolting caches and queues onto a database that was never built for your access pattern. "SQL or NoSQL?" sounds like a religious war, but at the senior level it is a calm engineering decision — one you make by looking at your data and how you touch it, not at which logo is trending.

The question this chapter answers

You have data to store. Do you reach for a relational database with tables and joins, or one of the NoSQL families — and how do you defend that choice when an interviewer pushes back with "but does it scale?"

Core Concepts

Relational (SQL) databases — PostgreSQL, MySQL, SQL Server — store data in tables: rows and typed columns, defined by a schema you declare up front. Their superpower is the relationship: you split data into normalised tables (users, orders, products) and stitch them back together at read time with joins. They give you ACID transactions (Atomicity, Consistency, Isolation, Durability) — the guarantee that a transfer either fully happens or fully doesn't, even if the server loses power mid-write. And they speak SQL, a declarative query language that makes ad-hoc questions ("total revenue per region last quarter") trivial. Fifty years of engineering have made them extraordinarily reliable. Their historical weakness: they were designed to scale up (a bigger machine), not out (many machines).

NoSQL ("Not Only SQL") is not one thing — it is four different answers to "what if we drop some of the relational guarantees in exchange for scale, flexibility, or a better-fitting data model?" Here is the landscape:

Rendering diagram…

The four NoSQL families, and when each earns its place

  • Key-value (Redis, DynamoDB, Memcached) — the simplest model: a giant dictionary. You GET and SET by key in roughly O(1), and that's mostly it — no rich queries. Perfect for caching, session stores, rate-limit counters, and leaderboards. Redis holds data in memory, so reads land in sub-millisecond territory versus single-digit milliseconds for a disk-backed relational read.
  • Document (MongoDB, Couchbase, DynamoDB) — stores self-contained JSON/BSON documents. There is no rigid schema, so each document can differ, and nested data (an order with its line items inside it) lives together and is read in one hit — no join. Great when your data is naturally hierarchical and your shape evolves fast, as in early-stage products or content management.
  • Wide-column (Cassandra, HBase, Bigtable) — rows keyed by a partition key, with columns grouped into families; designed for massive write throughput across many nodes with no single master. This is the home of time-series data, event logs, IoT sensor streams, and activity feeds at hundreds of thousands of writes per second.
  • Graph (Neo4j, Amazon Neptune) — data is nodes and edges, and traversing relationships ("friends of friends who like jazz") is a first-class, cheap operation. In a relational database the same query is a pile of self-joins that degrade fast with depth. Reach for graph when the connections are the product: social networks, fraud rings, recommendation graphs.
Everyday analogy

A relational database is a spreadsheet with strict, linked sheets — every row obeys the column headers, and a formula can join the Orders sheet to the Customers sheet. A document store is a drawer of folders: each folder holds one customer's whole story on its own pages, in whatever layout that customer needed — fast to grab, but there's no formula that reaches across all the folders at once. Key-value is a coat check: hand over the ticket number, get your coat, no questions asked. Graph is a corkboard of pinned photos joined by string — following the string is the whole point.

Why NoSQL arose

Through the 2000s, web-scale companies hit a wall relational databases weren't built for. A single Postgres box could be made enormous, but eventually you run out of "bigger machine," and scaling writes across many machines meant sharding by hand — painful, and joins across shards barely work. Meanwhile schemas that changed weekly fought against rigid ALTER TABLE migrations, and firehoses of write traffic (Amazon's cart, Facebook's feed) demanded throughput a single master couldn't sustain. NoSQL was the pragmatic answer: give up some of joins, strong consistency, and full ACID, and in return get horizontal scale, a flexible schema, and huge write throughput. That is the trade at the heart of the whole category — you are not getting scale for free; you are paying for it in guarantees.

History changed here

In 2007 Amazon published the Dynamo paper — a key-value store that chose availability and partition-tolerance over strong consistency, so the shopping cart never went down even when servers did. A year later Facebook released Cassandra, marrying Dynamo's distribution with Bigtable's data model. These two papers, plus Google's 2006 Bigtable, lit the fuse on the NoSQL movement. The name itself came from a 2009 meetup hashtag — it was never a considered brand, which is why "Not Only SQL" is the retrofitted, more honest reading.

The big comparison

This is the table to have in your head when the question comes:

Dimension Relational (SQL) NoSQL
Schema Fixed, declared up front; enforced Flexible / schema-on-read; varies per record
Scaling Vertical first; horizontal is hard (sharding) Horizontal-native; add nodes to scale out
Consistency Strong (ACID) by default Often eventual (tunable); strong is opt-in
Transactions Full multi-row ACID, first-class Limited historically; now common but narrower
Joins / relationships Rich joins across tables Usually none — you denormalise or embed
Query flexibility Excellent — ad-hoc SQL, aggregates Optimised for known access patterns; ad-hoc is weak
Best for Structured, related data; integrity; reporting Huge scale, simple lookups, flexible/evolving shape, write-heavy
The engineer's notebook

What experienced engineers actually weigh, quickly:

• Do the entities have real relationships I'll query across? Yes → SQL. Joins are a feature, not a smell.
• Is there money or a legal record involved? Then I want ACID transactions — the default answer is relational.
• Will I ever ask questions I can't predict today? SQL's ad-hoc queries are gold; most NoSQL punishes access patterns you didn't design for.
• Am I write-bound at enormous scale, or is my shape a self-contained blob? That's when a specific NoSQL family earns its keep — pick the one whose model matches, not the most popular one.

The nuance senior engineers insist on

Here is the line that separates a mid answer from a senior one: the old dividing lines have blurred. "SQL doesn't scale" is a decade out of date. NewSQL systems — Google Spanner, CockroachDB, Vitess (which shards MySQL, and is what powers YouTube and Slack) — deliver horizontal scale with SQL and ACID transactions. Postgres now stores and indexes JSON (JSONB) nearly as flexibly as a document store. Meanwhile the NoSQL world has moved the other way: MongoDB added multi-document ACID transactions in 2018, and DynamoDB supports transactions too. The clean "SQL = consistent but small, NoSQL = scalable but loose" mental model is now a caricature. Choose on your data model and access patterns — not on hype, and not on a slogan from 2010.

Real-world example — chika.ng Academy

The Academy runs on a single MySQL host with Drizzle as the query layer — a plain relational database, and the right call. Its data is deeply relational (students enrol in courses, courses have chapters, attempts belong to students and produce certificates) and it needs integrity: a certificate must map to exactly one real, passed attempt. The load is modest — one host handles it comfortably. Reaching for Cassandra here would add distributed-systems complexity to solve a scale problem that doesn't exist. The honest lesson: most applications are not web-scale, and a well-indexed relational database on one machine is the correct, unglamorous answer far more often than the internet implies.

How to choose — the decision framework

Don't start from the database. Start from the data:

  1. Model your entities and their relationships. Draw them out.
  2. List your access patterns — the actual reads and writes, with rough frequencies. This matters more than anything else.
  3. Then match:
    • Relationships + integrity + unpredictable/ad-hoc queries → SQL.
    • Simple key lookups at massive scale, or a flexible/evolving shape, or a write firehose → the matching NoSQL family.
  4. Expect to use more than one. Serious systems practise polyglot persistence — the right store for each job:
Rendering diagram…

One e-commerce system, three stores, each chosen for its access pattern: Redis for hot ephemeral state, a relational database for the money and the relationships, Cassandra for the high-volume append-only feed. That is not indecision — it is maturity.

Common Mistakes

  • Choosing by hype, not by data model. "We used MongoDB because it's web-scale" — for data that was deeply relational and never grew past one node. Match the model to the data, not to the conference talk.
  • Believing "SQL doesn't scale." Vitess, CockroachDB, and Spanner run some of the largest systems on earth. If you say this in a senior interview unchallenged, you've dated yourself.
  • Denormalising into NoSQL, then needing joins anyway. You embed everything to avoid joins, then discover you need to query across documents — and rebuild a worse join in application code.
  • Ignoring access patterns until after you've picked the store. NoSQL rewards a schema designed around your queries and punishes the ones you didn't foresee. Design the queries first.
  • Reaching for NoSQL to avoid schema design. "Flexible schema" is not "no schema" — it just moves the schema into your application code, where it's enforced less and breaks more quietly.
  • Forgetting transactions when money is involved. If a wrong balance is a lawsuit, you want ACID. Don't trade it away for scale you don't have.
Thought experiment

You're designing Twitter. A tweet is tiny and simple; a user has millions of followers; the home timeline is a firehose of writes (every tweet fans out to every follower's feed) but each read is "give me my feed." Now ask: which store for the user accounts and their relationships? Which for the timeline feed? Which for trending-topic counters updated thousands of times a second? If you reached for one database for all three, re-read the polyglot diagram. There isn't a single right store — there's a right store per access pattern, and naming three different ones is the senior answer.

Interview Corner

Interview Corner — the same idea at three levels. Answer yours; recognise the one above it.
Junior
"What's the difference between SQL and NoSQL?"
Model answer — "SQL databases store data in tables with a fixed schema and let you join related tables and run ACID transactions — great for structured, related data. NoSQL is a family of stores (key-value, document, wide-column, graph) that trade some of those guarantees for horizontal scale and a flexible schema. SQL asks 'what's the shape?' up front; most NoSQL lets the shape vary."
Follow-up they'll throw: "Name a NoSQL type and when you'd use it." → Key-value like Redis for caching and sessions; document like MongoDB for nested, evolving data.
Intermediate
"You're storing user sessions for a high-traffic site. SQL or NoSQL, and why?"
Model answer — "A key-value store like Redis. Sessions are simple — a session ID maps to a blob of state — so I need O(1) lookups by key, not joins or ad-hoc queries. Read/write volume is huge and latency-sensitive, and Redis serves from memory in sub-millisecond time. Sessions are also naturally ephemeral, so its TTL expiry fits perfectly. Putting this in a relational table would add overhead I get nothing back for."
Follow-up: "What do you lose?" → Durability and rich queries — but for sessions I don't need either, and I can enable Redis persistence if I want a safety net.
Senior
"Design the storage layer for an e-commerce platform at scale. Justify every choice."
Model answer — "Polyglot persistence, chosen by access pattern. Orders, payments, and inventory go in a relational database — they're deeply related and demand ACID, because a double-charged card or oversold item is a real-world failure. If write volume outgrows one node I'd reach for a NewSQL option like CockroachDB or Vitess rather than abandon transactions. The product catalogue, with its varied and evolving attributes, fits a document store. Hot data — cart, sessions, inventory counts — sits in Redis for sub-ms reads and to shield the primary database. The high-volume activity feed and clickstream go to a wide-column store like Cassandra for write throughput. The point isn't picking 'SQL or NoSQL' — it's refusing to force one store to do four jobs it's bad at."
The senior signal: leading with access patterns, defending ACID where money lives, and knowing NewSQL means 'SQL doesn't scale' is no longer a valid reason to drop relational.
Company lens — how the same topic gets asked
micro1Live and conversational — reason out loud. State your access patterns first, then map each to a store; narrating the why matters more than landing the "right" database.
GoogleExpects rigor and scale awareness — knows Spanner and Bigtable intimately. Be ready to quantify (QPS, data size) and to defend consistency vs availability trade-offs precisely.
MetaProduct-scale and pragmatic — think news feed, social graph. Expect graph-vs-relational discussions and fan-out-on-write reasoning; they value choices that ship.
AmazonOperational and cost lens — DynamoDB is home turf. Tie your choice to cost, availability, and operational load, and be ready to reason about eventual consistency (Leadership Principle: Dive Deep).
Hands-on exercise
  1. Pick an app you know (a ride-share, a chat app, a bank). List its top 5 access patterns, then sketch a polyglot-persistence diagram assigning each to a store — and label why.
  2. Say the trade-off out loud: in one breath, explain what you give up by choosing Cassandra over Postgres for order data — and what you'd need to be true for that to be the right call.
  3. Take a relational schema you know (say, users → orders → line-items) and rewrite one order as a single embedded document in ```json. Note one query that got easier and one that got harder.
  4. Defend, in two sentences, why chika.ng's Academy runs on one MySQL host rather than a NoSQL cluster — the way you'd defend it to an interviewer pushing "but does it scale?"

Chapter Summary

  • Relational (SQL) = tables, fixed schema, joins, ACID, strong consistency — the default for structured, related data that needs integrity and ad-hoc queries.
  • NoSQL is four distinct models: key-value (O(1) lookups, cache/sessions), document (flexible nested JSON), wide-column (massive write throughput), graph (relationship traversals).
  • NoSQL arose to win horizontal scale, flexible schemas, and write throughput — bought by giving up some joins, strong consistency, and full ACID.
  • The line has blurred: NewSQL (Spanner, CockroachDB, Vitess) scales SQL horizontally, and modern NoSQL added transactions. "SQL doesn't scale" is outdated.
  • Choose by data model and access patterns, not hype. Relationships + integrity + ad-hoc → SQL; simple lookups at scale / flexible shape / write-heavy → the matching NoSQL family.
  • Serious systems use polyglot persistence — several stores, each for the job it's best at.
  • Most apps aren't web-scale: a well-indexed relational database on one host is the right answer more often than the internet suggests.
Narrative bridge

We've chosen which database. But whichever we picked, one truth carries over from Volume 0's Big-O chapter: a query that scans every row falls off a cliff as the table grows. The thing that saves it — turning an O(n) full-table scan into an O(log n) lookup, whether in MySQL or MongoDB — is the same humble structure the certificate-verification example already leaned on. Next chapter: Database Indexing, the single highest-leverage skill for making any database fast.

Editorial reflection — the "SQL vs NoSQL" debate is loud because it's easy to have an opinion and hard to have the data. The engineers who navigate it well are almost boring about it: they draw the entities, list the reads and writes, and let the access patterns choose the store — often more than one. They know the flashy web-scale answer is the wrong answer for the 95% of systems that will never be web-scale, and they're unbothered by shipping "just Postgres" when Postgres is right. Fluency here isn't knowing every database. It's knowing which question to ask first — and it's always how will this data be used?

Q&A · 0

Enrol to ask questions and join the discussion.

No questions yet — be the first to ask.