Deep Dive
high level designdistributed systemsdatabases

Database Sharding: When One Machine Stops Being Enough

Your 4 TB users table no longer fits — or no longer keeps up with writes — on a single node. Sharding is the answer, and the shard key you pick quietly decides everything that follows.

·16 min read
Hard

The users table crossed 4 TB last quarter. It still fits on the box — barely — but the working set no longer fits in RAM, the nightly VACUUM runs into business hours, and a single primary now absorbs every write in the company. You’ve already added read replicas; reads are fine. The problem is that writes and storage both terminate at one machine, and you can’t buy a bigger one fast enough. You’ve hit the ceiling of vertical scaling. The only door left is to cut the table into pieces and spread them across many machines.

Why partition at all

Two independent pressures push you here, and it helps to name which one is biting. Data volume: the dataset outgrows one node’s disk or memory. Write volume: a single primary can’t absorb the write throughput, no matter how much RAM you throw at it (replicas scale reads, never writes). Sharding is the one move that attacks both — every shard owns a slice of the data and a slice of the writes. Chapter 6 of Designing Data-Intensive Applications frames the entire subject around exactly this: partitioning exists to scale beyond a single node.

Two ways to map a key to a shard

Every partitioning scheme is a variation on one question: given a key, which shard owns it? There are two honest answers, and they trade off against each other perfectly.

Range partitioning keeps keys ordered and hands each shard a contiguous range (A–F, G–M, …). Range scans and sorted reads are trivial — “all orders in January” is one shard, read sequentially. The cost: skewed data hot-spots one shard. Timestamp keys are the classic trap — today’s writes all land on the last range, so the newest shard melts while the rest sit idle.

Hash partitioning runs the key through a hash first, scattering it uniformly across shards. Load spreads evenly and no shard is inherently hotter. The cost: hashing destroys order, so a range scan now has to touch every shard and merge — the very query range partitioning made free.

all traffickey → shardrouterShard Akeys 0000–3FFFShard Bkeys 4000–7FFFShard C 🔥holds "post:celebrity"Shard Dkeys C000–FFFFfirehosemillions of hits
One keyspace split across four shards. Under range partitioning, adjacent keys cluster — so a burst on one range (here, the celebrity key on Shard C) overloads a single node while the others idle.
Range partitioning
  • Keys stay ordered — range scans and sorted reads hit one (or few) shards
  • Natural for time-series and "between X and Y" queries
  • Skew hot-spots a single range — sequential IDs / timestamps pile on the newest shard
  • Needs active rebalancing as ranges fill unevenly
Hash partitioning
  • Uniform spread — no shard is inherently hotter (for non-celebrity keys)
  • Great for point lookups by key
  • Destroys ordering — every range scan becomes a scatter-gather across all shards
  • A single hot key still overloads its one shard; hashing does not fix that

That single choice — range or hash — is only the opening move. The members-only continuation goes deep: the modern hash-plus-consistent-hashing default that keeps reshuffling bounded, the two shard keys for one orders table (with the routing code side by side) that produce completely different systems, salting a celebrity key, rebalancing without a stop-the-world, local vs. global secondary indexes, how Vitess, DynamoDB, Cassandra, and MongoDB actually shard in production, and an interview corner with a hands-on challenge and quiz.

Members only

Keep reading with Premium

You've reached the members-only part of this deep-dive — the full implementation, the interactive ring simulator, and the step-by-step walkthrough. Unlock it with a membership.

Related Articles