SQL vs NoSQL· 20 min

SQL vs NoSQL

When to use relational vs non-relational

NoSQLIntermediate20 min read

SQL databases are structured, relational, ACID. NoSQL trades structure for flexibility, scale, or specialization.

SQL vs NoSQL — When to Use What — diagram
🖱️ Drag nodes · Scroll to zoom · Drag background to pan
SQLPostgreSQL, MySQLFixed SchemaACIDJOINsVertical ScaleNoSQLMongoDB, RedisFlexible SchemaBASENo JOINsHorizontal Scale

Explanation

SQL: fixed schema, relational, ACID transactions, powerful queries (JOINs), vertical scaling. NoSQL types: Document (MongoDB), Key-value (Redis), Column-family (Cassandra), Graph (Neo4j). NoSQL scales horizontally, has flexible schemas, but weaker consistency (BASE).

Example

-- SQL: structured users + orders
CREATE TABLE users (id INT PK, name TEXT, email TEXT);
CREATE TABLE orders (id INT PK, user_id INT FK, total DECIMAL);
-- NoSQL (MongoDB): nested document
db.users.insertOne({ _id: ObjectId("..."), name: "Alice", email: "alice@x.com",
  orders: [{ id: 1, total: 99.99, items: [...] }] });

Key points

  • →SQL: relational data, JOINs, strong consistency
  • →Document: flexible/nested data (CMS, profiles)
  • →Key-value: caching, sessions
  • →Column-family: time-series, write-heavy
  • →Graph: relationships are the data

Quick interview answers

SQL for everything?
Modern Postgres handles JSON, full-text, time-series. For most apps, Postgres is enough.
Is NoSQL faster?
Not inherently. Faster for specific patterns (Redis for caching) but slower for complex queries.

DBMS deep dive

SQL vs NoSQL — When to Use What: deep dive

SQL vs NoSQL is really a question of access patterns and scaling limits, not old versus new. A strong answer starts from the queries the system has to serve and the consistency it needs, and only then picks a data model.

Start from the queries, not the data

Relational databases model the data and let you ask almost any question later through joins and ad-hoc SQL. Most NoSQL stores make you model the queries up front. In DynamoDB or Cassandra you design the partition key around the exact lookups the app will make, and a query you did not plan for may need a new table or index. That is the real trade: query flexibility in exchange for predictable performance at very large scale.

Worked example: one feature, two designs

Take a feature that shows the latest 50 messages in a chat room. In PostgreSQL you would write a messages table with an index on (room_id, sent_at DESC). In Cassandra you would design the table around that one query:

Same feature, relational vs wide-column
-- PostgreSQL: normalized, flexible, joins available
CREATE TABLE messages (
  id BIGSERIAL PRIMARY KEY,
  room_id BIGINT NOT NULL REFERENCES rooms(id),
  author_id BIGINT NOT NULL REFERENCES users(id),
  body TEXT NOT NULL,
  sent_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX ON messages (room_id, sent_at DESC);

-- Cassandra (CQL): table shaped for one query, no joins
CREATE TABLE messages_by_room (
  room_id     uuid,
  bucket      text,          -- e.g. '2026-10' keeps partitions bounded
  sent_at     timeuuid,
  author_name text,          -- denormalized copy, no join to users
  body        text,
  PRIMARY KEY ((room_id, bucket), sent_at)
) WITH CLUSTERING ORDER BY (sent_at DESC);

The Cassandra version spreads writes across nodes and serves the query from one partition. But if a user changes their name, every old message keeps the stale author_name until you rewrite it. 'Show all messages by user X' would need a second table. The relational version answers both with one index, and it is the right choice until one primary can no longer keep up.

A decision table

RequirementLeans towardWhy
Multi-row invariants (money, inventory)RelationalCross-row ACID transactions and constraints
Ad-hoc analytics and reportingRelational or a warehouseJoins, aggregates, a mature optimizer
Huge write throughput, simple key accessWide-column (Cassandra, ScyllaDB)Log-structured storage, leaderless replication
Self-contained documents with varied shapesDocument (MongoDB) or Postgres JSONBRead or write the whole aggregate at once
Sub-millisecond lookups, ephemeral dataKey-value (Redis)In-memory data structures
Multi-hop relationship queriesGraph (Neo4j)Follows edges directly instead of making repeated joins
Predictable latency at any scale, serverlessDynamoDBManaged partitioning, single-digit-ms key lookups

Consistency is a spectrum, not a label

'NoSQL means eventual consistency' is outdated. Cassandra lets you choose per query: with replication factor 3, writing and reading at QUORUM gives R + W > N, so every read overlaps the latest write. DynamoDB offers strongly consistent reads on request. MongoDB has multi-document transactions. Meanwhile a Postgres read replica is eventually consistent too. PACELC is a useful frame here: during a partition you choose availability or consistency, and the rest of the time you still trade latency against consistency.

Scaling also is not a binary choice. Postgres scales reads with replicas and writes with partitioning, or with sharding through tools like Citus. Distributed SQL systems such as CockroachDB, Spanner and YugabyteDB offer SQL with horizontal writes, at the cost of higher commit latency.

Common mistakes

  • Picking NoSQL for 'scale' at a data size one Postgres instance handles comfortably.
  • Using a document store for highly relational data and then rebuilding joins in application code.
  • Calling NoSQL 'schemaless'. The schema still exists, but it lives in application code (schema-on-read), and every reader has to handle old shapes.
  • Unbounded partitions in Cassandra or DynamoDB, such as all events for one user forever, which create hot partitions.
  • Ignoring operations: backups, migrations and the tooling your team already knows.

Interview questions

›What is the difference between schema-on-write and schema-on-read?

Schema-on-write, as in SQL, rejects bad data at insert time through types and constraints. Schema-on-read, as in most document stores, accepts any shape and leaves the interpretation to readers. Evolution is easier, but versioning moves into application code.

›What is a hot partition, and how do you avoid it?

It is one partition key that receives a large share of the traffic, so one node becomes the bottleneck. Avoid it with high-cardinality keys, write sharding (adding a suffix such as key#0..N), and time bucketing for time-series data.

›Why do NoSQL designs denormalize, and what does it cost?

Without joins, one query should hit one partition, so data is copied into each table that needs it. The cost is write amplification and keeping the copies consistent, often through async fan-out or change streams.

›When is Postgres JSONB a better choice than MongoDB?

When most of the data is relational but some attributes vary, such as product specs. JSONB with a GIN index gives flexible fields alongside joins, foreign keys and transactions in one system.

›How would you migrate a growing Postgres app that is hitting write limits?

First rule out the cheaper fixes: indexes, batching, connection pooling and table partitioning. Then shard by a tenant or user key, using Citus or application-level routing, or move the hot write path, such as events, to a store built for append-heavy load.

More Database Management Systems

Compare this lesson with the other 8 concepts in the course. Expand any card for its design, trade-offs and diagram.

Category:
Difficulty:
Showing 8 of 8