SQL vs NoSQL
SQL databases (PostgreSQL, MySQL) store data in tables with strict schemas and support ACID transactions. NoSQL databases (Cassandra, MongoDB, DynamoDB) trade strict consistency for scalability, flexibility, or performance. The choice depends on your data shape, consistency requirements, and scale.
How it works
The SQL vs NoSQL choice is not about which is 'better' — it's about which trade-offs fit your problem. SQL databases excel at structured data, complex queries, and ACID transactions. NoSQL databases excel at scale, flexible schemas, and specific access patterns.
The key insight: NoSQL is not one thing. It's an umbrella for several different database models — key-value, document, wide-column, graph — each with different trade-offs.
SQL strengths:
- ACID transactions: multi-operation, all-or-nothing. Critical for payments, inventory, bookings.
- Structured schema: columns and types are enforced. Prevents bad data.
- JOINs: query across related tables efficiently.
- Mature ecosystem: ORMs, tooling, decades of optimization.
- Consistency: strong (linearizable) by default.
SQL weaknesses:
- Vertical scaling: hard to shard across machines.
- Schema changes: migrations are painful at scale.
- Impedance mismatch: relational model doesn't map cleanly to objects.
NoSQL types:
- Key-value (Redis, DynamoDB): simplest. Key → value. Extremely fast. No query complexity.
- Document (MongoDB, CouchDB): key → document (JSON). Flexible schema. Good for content, profiles, catalogs.
- Wide-column (Cassandra, HBase): rows with dynamic columns. Good for time-series, high-write throughput.
- Graph (Neo4j): nodes and edges. Good for social networks, recommendation engines, fraud detection.
Each is optimized for a specific access pattern. Choosing the right NoSQL type requires knowing your query patterns.
- Need ACID transactions (payments, inventory)? → SQL (PostgreSQL).
- Need massive write throughput (time-series, logs)? → Wide-column (Cassandra).
- Need flexible schema (content, user profiles)? → Document (MongoDB).
- Need sub-millisecond reads (cache, counters)? → Key-value (Redis).
- Need complex relationships (social graph, recommendations)? → Graph (Neo4j).
- Not sure? Start with PostgreSQL. You can migrate later if needed.
You're building a payment system that handles credit card charges. Which database should you use?
Pick one answer.
You're building a system that logs 1 billion events per day (time-series data). Which database is best suited?
Pick one answer.
| Dimension | SQL (PostgreSQL, MySQL) | NoSQL (Cassandra, MongoDB, DynamoDB, Redis) |
|---|---|---|
| Data model | Tables, rows, columns, foreign keys | Key-value, document, wide-column, graph — varies by type |
| Schema | Strict, enforced by DB; migrations are expensive | Flexible / schema-on-read; schema enforced by app |
| Joins | Native, optimized, ACID across joined tables | Limited or none; denormalize to avoid |
| Transactions | ACID (atomic, consistent, isolated, durable) | Often BASE (basically available, soft state, eventual consistency); some support per-partition ACID |
| Consistency | Strong (linearizable) by default | Tunable / eventual by default; some offer strong on single partition |
| Scaling model | Vertical primary + read replicas; horizontal via sharding is hard | Built for horizontal sharding; add nodes and rebalance |
| Query language | SQL (declarative, standard) | DB-specific (CQL, MongoDB Query Language, Redis commands) |
| Best at | Complex queries, multi-row transactions, financial data, structured data | Massive write throughput, flexible schema, single-key lookups, global distribution |
| Worst at | Horizontal scaling beyond a few shards, schema churn, very high write QPS | Multi-entity transactions, JOINs, ad-hoc analytics, referential integrity |
| Maturity | 40+ years, huge ecosystem, well-understood failure modes | 15-ish years, smaller ecosystems, more surprises at scale |
| Default choice | PostgreSQL — until you outgrow it | Only when SQL doesn't fit the access pattern |
ACID (SQL's promise): Atomic — all-or-nothing transactions. Consistent — DB enforces invariants (foreign keys, constraints). Isolated — concurrent transactions don't see each other's partial writes. Durable — committed writes survive crashes. ACID trades latency and availability for correctness. Use when a half-completed transaction is worse than a failed one (payments, bookings, inventory).
BASE (NoSQL's promise): Basically Available — system remains responsive under failure. Soft State — application reconciles state over time. Eventually Consistent — replicas converge given enough time. BASE trades correctness for availability and partition tolerance. Use when stale data is acceptable (social feeds, dashboards, logs).
The two are not 'right vs wrong' — they're different points on the CAP trade-off curve. Most real systems use both: SQL for transactional core (payments, users, inventory) and NoSQL for the read-heavy / write-heavy periphery (feeds, analytics, cache).
Real example: Uber's polyglot persistence.
Uber's stack uses different databases for different access patterns (documented across years of engineering blog posts):
- Schemaless on MySQL for trips, users, drivers — sharded by UUID, high-write-throughput, eventually consistent across regions. Custom store they built because no off-the-shelf DB fit their write profile + global consistency needs.
- PostgreSQL for billing and financial data — ACID transactions, foreign keys, auditable. Worth the cost of a stricter scaling story because the cost of a double-charge or lost-charge is so high.
- Cassandra for location tracking (driver positions updated every few seconds per driver; hundreds of thousands of writes/sec; reads are 'where are drivers near this rider'). Massive write throughput, time-series friendly.
- Redis for caching (hot trip state, rate-limit counters, session data). Sub-millisecond reads, in-memory, accepts data loss on crash for the cache use case.
- Elasticsearch for full-text search (rider destination autocomplete, driver destination search). Inverted-index optimized for relevance-ranked text queries.
- Kafka for event streaming (every trip event flows through Kafka; downstream consumers derive analytics, billing, fraud signals).
Why so many? Because each access pattern has a different optimal storage primitive. Trying to do all of this in one database means either (a) the financial data loses ACID guarantees (dangerous) or (b) the location tracking can't keep up with writes (system failure). Polyglot persistence — using different databases for different access patterns — is the standard pattern at scale. The cost: more infrastructure to operate, more schemas to keep in sync, more failure modes to understand. The rule of thumb: don't introduce a new database until the cost of operating it is less than the cost of forcing your existing DB to do something it's bad at.
You're designing the data layer for a ride-sharing app. Which of these database assignments is the strongest argument for polyglot persistence?
Pick one answer.
PostgreSQL jsonb — the bridge that often eliminates the need for NoSQL.
A common architectural mistake is choosing MongoDB for 'flexible schema' when PostgreSQL has had jsonb (binary JSON) since 9.4 (2015). jsonb stores arbitrary JSON in a binary format, supports indexing via GIN indexes, and lets you query nested fields with SQL operators. The result: many workloads that 'need NoSQL' actually just need flexible schema in a single table — and PostgreSQL can do that without giving up ACID, JOINs, or transactions.
Example schema that bridges the gap:
CREATE TABLE events (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL,
event_type TEXT NOT NULL,
payload JSONB NOT NULL, -- flexible per-type schema
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Index the JSON for fast lookups
CREATE INDEX idx_events_payload ON events USING GIN (payload jsonb_path_ops);
-- Index user_id + created_at for time-range queries
CREATE INDEX idx_events_user_time ON events (user_id, created_at DESC);Now you can query with both structured (SQL) and document (JSON) operations:
-- Find login events for user 42 in the last hour with browser=Chrome
SELECT * FROM events
WHERE user_id = 42
AND event_type = 'login'
AND created_at > NOW() - INTERVAL '1 hour'
AND payload->>'browser' = 'Chrome';When does this NOT suffice, and you really do need NoSQL?
- Write throughput beyond ~50K writes/sec on a single primary — Cassandra or DynamoDB scale horizontally where PostgreSQL can't.
- NoSQL-style horizontal sharding is core — Cassandra, DynamoDB, and MongoDB shard transparently; PostgreSQL sharding (Citus) is good but adds operational complexity.
- Schema is truly schemaless and evolves per record — e.g., user-generated forms. Document stores handle this natively; SQL requires the jsonb escape hatch.
The decision rule: reach for PostgreSQL + jsonb first. Switch to a document store only when you've proven the jsonb path can't meet your write throughput or scaling needs. The cost of being wrong in this direction is small (a migration); the cost of starting with NoSQL and realizing you needed ACID is much larger.
Engineering mental model
Mental model. Think of SQL vs NoSQL as a deliberate boundary in a system. The boundary exists because something becomes harder to manage when everything is done in one place: latency, scale, failure isolation, consistency, cost, or team ownership. The useful question is not “what does SQL vs NoSQL mean?” but “what pressure makes this boundary worth introducing, and what new failure mode does it create?”
Before choosing SQL vs NoSQL, name the workload, the critical user path, the dominant bottleneck, the failure you are trying to absorb, and the trade-off you are willing to accept. If you cannot name those five things, the design is probably premature.
SELECT id, created_at
FROM records
WHERE tenant_id = ?
ORDER BY created_at DESC
LIMIT 50;
-- Ask: which index makes this query predictable at scale?Back-of-the-envelope reasoning
Numerical lens: write down traffic, payload size, read/write ratio, peak multiplier and durability target before choosing a component. The numbers should justify the architecture.
Interactive thought experiment: SQL vs NoSQL
Change the variables below and predict what breaks first in SQL vs NoSQL. The production lab can later reuse these same inputs.
Change one variable at a time. Predict the failure mode first, then move the slider and see whether your mental model matches the simplified system response.
If you are stuck on SQL vs NoSQL, start by drawing the request path and marking every network hop, stateful component, queue, cache and failure boundary. Then estimate where the system will saturate.
You increase traffic by 10× in a system using SQL vs NoSQL. What should you inspect first?
Pick one answer.
Which statement is the safest engineering habit when using SQL vs NoSQL?
Pick one answer.
You have dashboards for traffic, latency, errors and saturation. You can change the architecture, but every change has operational cost.
Production scenario: your system uses SQL vs NoSQL, traffic suddenly spikes, and p99 latency doubles. What is your first move?
Interview drill
Answer this without notes: When would you choose SQL vs NoSQL, and when would you intentionally avoid it? Mention at least one bottleneck it addresses, one failure mode it introduces, and one alternative. Then quantify the workload you are designing for.
For SQL vs NoSQL, start with access patterns rather than brand names. Identify the dominant reads/writes, data relationships, consistency requirements, partition key, hot keys and failure behavior before choosing a storage strategy.
Numerical sanity check
A rough capacity check: required write throughput ≈ peak writes/s × average record size. At 5,000 writes/s and 2 KB average payloads, the raw incoming data stream is about 10 MB/s before indexes, replication and overhead.
Do not optimize for a memorized definition. Reason from the workload and failure mode.
A team proposes SQL vs NoSQL because it 'scales'. What workload characteristic would make that choice a poor fit?
Pick one answer.
What you gain, what you pay
- +SQL: ACID, JOINs, mature ecosystem, strong consistency.
- +NoSQL: horizontal scalability, flexible schema, high throughput for specific patterns.
- +NoSQL: each type is optimized for a specific use case (KV=speed, document=flexibility, wide-column=throughput, graph=relationships).
- −SQL: hard to shard, schema migrations are painful, vertical scaling ceiling.
- −NoSQL: eventual consistency (usually), no JOINs (must denormalize), less mature tooling.
- −NoSQL: each type is a specialist — wrong choice = bad performance.
How this breaks in production
- Using NoSQL for transactional data — loses ACID guarantees.
- Using SQL for massive write throughput — can't scale writes without sharding.
- Choosing a NoSQL type without understanding query patterns — e.g., using MongoDB for graph queries.
- Polyglot persistence without clear boundaries — too many databases to maintain.
Don't fall into these traps
- •Treating 'NoSQL' as one thing — it's 4 different models with different trade-offs.
- •Choosing NoSQL for 'scalability' without understanding your consistency needs.
- •Using SQL when your data is naturally a graph — SQL JOINs for graph queries are slow.
- •Forgetting that PostgreSQL can handle JSON (jsonb) — you might not need MongoDB.
Real systems using this
How real systems implement this
- Uber — Uses Schemaless (built on MySQL) for most data, Redis for caching, and Cassandra for location tracking. Polyglot persistence.
- Netflix — Uses Cassandra for viewing history (massive writes), EVCache (Redis) for caching, and MySQL for billing (ACID required).
Practice saying it out loud
- Q1When would you choose SQL over NoSQL?
- Q2What are the different types of NoSQL databases?
- Q3Can you use both SQL and NoSQL in the same system? When?
Further reading & references
Core explanations are original NO CAP material. External references are provided for deeper study and standards.
What next?
Mark as understood once the mental model clicks.
Next recommended
Key-Value Stores