Skip to main content
PProfileMatch

Databases in System Design: SQL vs NoSQL, Replication and Sharding

System Design & ArchitectureLesson 4 of 66 min read

What you'll learn

  • Compare SQL and NoSQL databases and explain ACID vs BASE
  • Explain how indexes speed up reads and what they cost on writes
  • Use leader-follower replication for read scaling and understand replication lag
  • Choose a sharding key and avoid hot partitions and cross-shard pain

On this page

  1. SQL vs NoSQL: choosing by access pattern
  2. ACID vs BASE
  3. Indexes: faster reads, slower writes
  4. Replication: scaling reads and surviving failures
  5. Sharding: splitting data across nodes
  6. Common mistakes
  7. How this shows up in interviews and real projects

In an e-commerce checkout, the order must be saved exactly once, stock must go down by exactly the right amount and a payment must never be charged twice. Meanwhile the product catalogue is read a thousand times more often than it changes. Different data has different needs, and the database choice is where those needs meet reality.

SQL vs NoSQL: choosing by access pattern

Relational (SQL) databases such as PostgreSQL and MySQL store data in tables with a fixed schema, support joins and offer strong transactional guarantees. NoSQL is an umbrella term for several different models: key-value stores, document databases, wide-column stores and graph databases. They typically trade rich querying and strict guarantees for flexible schemas and easier horizontal scaling.

SQL (relational)NoSQL (varies by type)
Data modelTables, rows, foreign keysKey-value, documents, wide-column, graph
SchemaDefined up front, enforcedFlexible or schema-on-read
QueriesRich: joins, aggregates, ad hocOptimised for known access patterns
TransactionsMulti-row ACID transactions are standardOften limited to a single item or partition (varies)
ScalingVertical and read replicas first; sharding is manual workDesigned to partition across many nodes
Good fitOrders, payments, inventory, anything relationalSessions, feeds, event logs, catalogues, time series

A sound default is to start with a relational database. It handles far more load than many people expect, and you can always move specific high-volume data to a specialised store later. Reach for NoSQL when you have a clear reason: a simple access pattern at very large scale, flexible document shapes, or write volumes that a single relational node cannot absorb.

ACID vs BASE

ACID describes the guarantees of a classic transaction: Atomicity (all steps happen or none do), Consistency (the data respects its rules after the transaction), Isolation (concurrent transactions do not see each other's half-finished work) and Durability (committed data survives a crash). Checkout is a textbook case: reducing stock, creating the order and recording the payment must succeed or fail together.

BASE (Basically Available, Soft state, Eventually consistent) describes the looser model many distributed NoSQL systems adopt: the system stays available even when nodes disagree for a while, and replicas converge over time. A "like" counter or a view count can tolerate being off by a few for a few seconds; a bank balance cannot. Many real systems use both, each for the data that suits it.

Indexes: faster reads, slower writes

Without an index, finding all orders for one user means scanning every row. An index (commonly a B-tree) is a sorted structure that lets the database jump straight to matching rows. The trade-off is that each index uses storage and must be updated on every insert, update and delete, so more indexes mean slower writes.

orders.sql
CREATE TABLE orders (
  id          BIGINT PRIMARY KEY,
  user_id     BIGINT      NOT NULL,
  status      VARCHAR(20) NOT NULL,
  total_cents BIGINT      NOT NULL,
  created_at  TIMESTAMP   NOT NULL
);

-- Composite index: filter by user, then sort by newest
CREATE INDEX idx_orders_user_created
  ON orders (user_id, created_at DESC);

-- Served efficiently by the index above
SELECT id, status, total_cents
FROM orders
WHERE user_id = 42
ORDER BY created_at DESC
LIMIT 20;

Design indexes from your real queries. Put equality filters first and the sort column after, keep the index narrow, and check the plan with EXPLAIN instead of guessing. Index columns you filter or join on; do not index every column.

Replication: scaling reads and surviving failures

In leader-follower replication, one node (the leader) accepts writes and copies them to followers, which serve reads. This scales read-heavy workloads, gives you standby copies for failover and lets you run backups and analytics away from the main node.

Leader with read replicas
        writes
          |
          v
    +------------+
    |   Leader   |
    +------------+
      |    |    |    replicate (usually async)
      v    v    v
 +------+ +------+ +------+
 | Rep1 | | Rep2 | | Rep3 |   <-- reads
 +------+ +------+ +------+

The catch is replication lag. With asynchronous replication a follower can be slightly behind, so a user who just updated their profile might read the old version from a replica. Common fixes are to read the user's own recent writes from the leader ("read your writes"), or to route that session to the leader for a short time. Synchronous replication removes the lag but makes every write wait for followers and hurts availability if one is slow.

Sharding: splitting data across nodes

Replication copies the same data everywhere, so it cannot help when the data or the write rate outgrows one machine. Sharding (horizontal partitioning) splits the data so each node holds only a slice. The most important decision is the shard key, the field that decides where a row lives.

Hash-based sharding
 App server
    |  shard = hash(user_id) % 3
    v
 +--------+   +--------+   +--------+
 | Shard0 |   | Shard1 |   | Shard2 |
 | users  |   | users  |   | users  |
 | A-slice|   | B-slice|   | C-slice|
 +--------+   +--------+   +--------+
 (each shard normally has its own replicas)
ApproachHowProsCons
Range-basedKey ranges per shard (A-H, I-P, ...)Efficient range scansProne to hot spots (e.g. newest IDs all land on one shard)
Hash-basedhash(key) mod N picks the shardEven spreadRange queries touch all shards; changing N moves most keys
Consistent hashingKeys and nodes placed on a ringAdding a node moves only a small share of keysMore complex to implement and operate
Directory-basedA lookup table maps key to shardMaximum flexibilityThe directory is a bottleneck and a SPOF unless made reliable

Plain hash(key) % N is easy but brittle. Going from 3 shards to 4 changes the result for about three quarters of all keys, which means moving most of your data. Consistent hashing, or a fixed larger number of logical partitions mapped to physical nodes, avoids that.

Hot partitions

Even a hash key can create a hot partition. If you shard a social app by user_id, one celebrity account with millions of followers sends disproportionate traffic to its shard. If you shard by created_at, every new write hits the latest shard. Choose a key with high cardinality and even access, and for known hot keys add a random suffix ("salting") to spread them, at the cost of reading from several places.

Common mistakes

  • Choosing NoSQL because it "scales" without a reason. Symptom: you rebuild joins and transactions by hand in application code, with bugs.
  • Missing or wrong indexes. Symptom: queries get slower as the table grows, and one slow query saturates the database.
  • Over-indexing. Symptom: slow inserts and updates, and large storage bills from indexes that no query uses.
  • Reading from a replica right after a write. Symptom: users save a change and then see the old data. Route read-your-writes traffic to the leader.
  • A poor shard key. Symptom: one shard runs hot while others are idle, so adding shards does not help.
  • Forgetting backups and failover. Replication is not a backup: a bad delete is replicated to every follower too.

How this shows up in interviews and real projects

Expect questions such as "SQL or NoSQL for this, and why?", "how would you scale the database?" and "what is your shard key?". Answer by naming the access patterns and consistency needs first, then the choice. In real projects most teams stay on a single relational primary with replicas for a long time, and shard only the data that forces it. The next lesson, CAP Theorem and Consistency Models, explains what happens when replicas cannot agree. See also the system design interview prep guide.

Try it yourself

For an e-commerce platform, choose a database type for each: user accounts, orders and payments, product catalogue, shopping cart sessions, and product view counters. Justify each choice with the access pattern and consistency requirement. Then pick a shard key for orders and explain one hot-partition risk.

Show a hint

Orders and payments need ACID transactions (relational). Sessions and counters fit a key-value store. Sharding orders by user_id keeps one user's orders together, but a bulk buyer or reseller could create a hot shard.

Key takeaways

  • Choose the database from access patterns and consistency needs; relational is a strong default, and NoSQL is a specific tool for specific needs.
  • ACID gives all-or-nothing transactions; BASE accepts temporary inconsistency in exchange for availability and scale.
  • Indexes make reads fast and writes slower; design them from real queries and verify with EXPLAIN.
  • Read replicas scale reads but introduce lag; sharding scales writes and storage but adds heavy complexity.
  • A good shard key has high cardinality and even load; watch for hot partitions.

Test yourself

A trick from this lesson's ride: ACID: all-or-nothing, rules kept, no peeking, survives a crash. Four more tricks like it wait along the route, each followed by a question.

Ride this lesson

Frequently asked questions

When should I use SQL vs NoSQL?

Use SQL when your data is relational and you need joins, ad hoc queries and multi-row transactions, such as orders and payments. Use NoSQL when your access pattern is simple and known, you need flexible schemas, or write volume and data size exceed what a single relational node can handle.

What is database sharding and when is it needed?

Sharding splits a dataset across multiple database nodes by a shard key so each node stores and serves only part of the data. It is needed when write throughput or data size outgrows a single machine, after simpler options such as indexing, caching and read replicas have been used.

What is the difference between ACID and BASE?

ACID provides strict transactional guarantees: atomicity, consistency, isolation and durability. BASE relaxes them to stay available and scalable: basically available, soft state and eventually consistent. ACID suits money and inventory, while BASE often suits feeds, counters and caches.