Limited time: AI code review, hints, mock interviews, whiteboard analysis, and all Pro features are unlocked. Enroll
⏱️ 15 min read

SQL vs NoSQL

Most comparisons of these two answer a question nobody has. You are not choosing between a table and a document in the abstract, you are choosing a store for a specific workload under interview time pressure. Here is how that decision actually goes.


The Short Answer

Default to a relational store. Move off it when you can name the specific access pattern that defeats it. If you cannot name the pattern, you are guessing, and the interviewer can tell.

That inverts the advice people absorbed around 2012. The reason is that the premise changed: β€œSQL does not scale” is no longer true in the way it was repeated. MySQL shards behind Vitess, Postgres shards behind Citus, CockroachDB and Spanner do distributed SQL with cross-shard transactions, and managed Aurora and AlloyDB push a single logical primary much further than a 2010 box could. Both Notion and Figma have published accounts of sharding Postgres instead of migrating off it.

Your situation Pick
You cannot yet describe every query the product will need Relational
Two rows must change together or not at all Relational
One known read shape, enormous write volume, no ad-hoc queries Wide-column or key-value
Reads are by one key and you want a fixed cost per operation Key-value
Full-text relevance, facets, typo tolerance Search index, alongside something else
Append-only measurements queried by time range Time-series store

Nothing in that table is about data volume.


What Each One Actually Optimises For

Relational stores optimise for querying data whose shape you cannot fully predict, and for invariants that span rows. You normalise once, and every future question is a join away. A BEGIN ... COMMIT holds several tables consistent with each other, which is the only reasonable place to put β€œdecrement inventory and create the order, or do neither”. The optimiser is doing work on your behalf that you would otherwise write by hand.

NoSQL stores optimise for one known access pattern at predictable cost, and treat horizontal distribution as a built-in rather than a project. You model the table as the answer to a query you already have. Cassandra and DynamoDB do not reward you for normalising - they reward you for writing the data once per read shape, so that serving it is a single partition lookup whose latency does not drift as the dataset grows.

The framing you should drop is structured versus unstructured. Postgres has stored JSON with GIN indexes for a decade, and a MongoDB collection has a schema in every meaningful sense - it is just enforced in your application code instead of by the engine, which is strictly worse for catching drift. Shape is not the axis. Query flexibility, transaction scope, and who owns the distribution problem are.


Side by Side

Β  Relational (Postgres, MySQL) NoSQL (Cassandra, DynamoDB, MongoDB)
Data model Normalised tables, relationships as foreign keys Denormalised per access pattern, relationships duplicated
Query flexibility Any query the data supports, decided later The queries your keys support, decided up front
Transactions ACID across many rows and tables Single partition or single document by default. DynamoDB and Mongo offer multi-item transactions with tight limits; Cassandra offers lightweight transactions at a steep latency cost
How scaling works Vertical first, then read replicas, then sharding you plan and run Add nodes, the ring or partition map rebalances
Consistency default Strong on the primary, replicas lag Tunable. Often eventual unless you pay for a quorum or strong read
Schema evolution Explicit migrations, enforced, occasionally painful on huge tables No migration step, so old and new shapes coexist and your code handles both forever
Joins Native, optimised, planner picks the strategy None or heavily limited. You denormalise, or you join in the application
Operational pain Sharding, connection limits, long-running migrations, failover of a stateful primary Modelling mistakes are near permanent, compaction and repair tuning, hot partitions, surprise bills

The transactions row is where most interview answers are vague. β€œNoSQL has transactions now” is technically true and practically misleading - DynamoDB caps a transaction at 100 items, and Cassandra’s lightweight transactions use Paxos per operation, so people who have run them do not use them on a hot path.


The Four Questions That Actually Decide It

1. Do you need multi-entity atomic writes?

Not β€œdo you want them”. Is there a pair of writes where a partial failure leaves the system wrong in a way a user would notice? Order plus payment. Seat hold plus booking. Balance debit plus balance credit.

If yes, a relational store is the cheap answer, because the database already solved it. The alternative is a saga with compensating transactions, which is a correct pattern and roughly ten times the work, and which leaves you with intermediate states that are visible to readers. Pick that deliberately, not by accident.

2. Do you know your access patterns up front?

A DynamoDB or Cassandra schema is a commitment to a set of queries. Get the partition key right and the store is fast and cheap forever. Get it wrong and the fix is a new table plus a backfill of everything, because there is no index you can add to rescue a bad key.

So the real question is how confident you are. A metrics ingest path or a chat message store has patterns that will not change. A product’s core domain in month three does not.

3. Do you need ad-hoc queries you have not thought of yet?

Someone will ask for revenue by region by week, filtered to customers who did something else. In Postgres that is a query. In Cassandra it is a Spark job or a new table, and the business waits.

This is the single most underrated advantage of a relational store, and the one candidates never mention.

4. What is your real write throughput per partition?

Not total throughput - per partition. This is the question that tells you whether you actually have a scale problem.

Work out the number. 100 million writes a day is about 1,200 per second averaged, maybe 5,000 at peak, and that is a single Postgres primary with room to spare. Two million writes a second to a location table is not, and no amount of tuning changes that.

Then check the concentration. DynamoDB documents a per-partition ceiling of 1,000 write units and 3,000 read units, and Cassandra’s own guidance is to keep a partition under a few hundred megabytes. If your key is country_id you have built a hot partition and the engine’s total capacity is irrelevant - you will be throttled on one shard while the other 99 idle.
πŸ’‘ A hot partition is a shard that receives a disproportionate share of traffic because the partition key has low cardinality or a skewed distribution. No database makes this go away; it is a modelling bug.


Where Each Family Fits


Using Both Is Normal

Polyglot persistence is the usual end state, not a compromise. A food delivery system is a clean example, and it is how the Zomato design on this site is put together:

The interesting engineering is the sync. Writing to Postgres and then publishing to Kafka in application code gives you two operations that can fail independently, and eventually the catalog or the search index disagrees with the truth. Use the outbox pattern: write the row and the event to the same database in one transaction, then a change data capture process tails the log and publishes. Atomic because it is one commit, and the index converges because the log is replayable.

Say the lag out loud when you present this. A search index a few seconds behind is fine. A balance a few seconds behind is a bug.


What Interviewers Actually Want to Hear

They are listening for whether you reasoned from the workload or recited a property list. Two answers, same candidate knowledge, very different signal:

β€œI will use NoSQL for the feed because it scales better and the data is unstructured.”

β€œThe feed is read by user id, newest first, about 50 items, and written at roughly 40K per second with no ad-hoc queries. So Cassandra, partition key user id, clustering key timestamp descending. What I give up is any query I did not plan for, and if product asks for β€˜most liked posts this week’ I need a separate table or a batch job.”

The second one names the access pattern, the key, and the thing being traded away. That is the whole game. A few shapes that land:

Saying β€œI would benchmark this before committing” is a good answer, not a dodge, as long as you also commit to a starting point.


Common Mistakes

Mistake Why it costs you
β€œNoSQL, because the data is large” Volume is handled by sharding or partitioning in either family. Size alone decides nothing, and leading with it signals you have not thought about queries
β€œNoSQL is schemaless” The schema moved into your application, where nothing enforces it. Three years of accumulated shapes and every reader handles all of them
Ignoring the hot partition One key taking a disproportionate share of writes caps you well below the cluster’s rated throughput. Every engine, no exceptions
Eventual consistency for money A balance read that is 200ms stale lets the same funds be spent twice. Ledgers want a strong read, or an idempotency key plus a conditional write
Forgetting where the joins went Removing joins from the database does not remove the work. It becomes N+1 round trips in your service, or duplicated data you now have to keep in sync
Picking the store before the access pattern The pattern determines the key, the key determines the store. Running that backwards is how teams end up with a table they cannot query and cannot migrate

Where to Go Next

The mechanics behind this decision, in roughly the order they come up:

Designs where the choice is made concretely, with reasons:


← Back to Concepts Next: Database Sharding β†’

Free system design + DSA prep. If it helped you crack an interview, consider supporting.

SensAI SensAI
Beta
Listening...
Tap mic to stop voice mode

Shape what we build next

Every piece of feedback is read by the team and directly influences our roadmap.

What type of feedback?

Install SystemCraft

Add to your home screen for instant access, offline reading, and a distraction-free experience.

Offline reading Faster loads No browser tabs App-like feel

Unlock AI Features

One click to activate - no payment, no credit card. Just sign in and you're in.

AI code review and hints
SensAI chat assistant
AI mock interviews
Whiteboard analysis
100% free during early access