Sharding: Splitting the Data Itself

Eventually one database server runs out of room — too many rows, too many writes, too much for a single machine to hold. Sharding (horizontal partitioning) splits one logical dataset across many database nodes, so each shard owns only a subset of the rows. Capacity now scales by adding machines instead of buying a bigger one. The catch: the moment your data lives on more than one node, every decision — which key to split on, how to route a query, how to rebalance — gets harder.

CONCEPT

Vertical Scaling vs Horizontal Partitioning

Scaling up means giving one server more CPU, RAM, and disk. Simple, but there is a hard ceiling — and the biggest machine is expensive and still a single point of failure. Sharding scales out: it slices the table by row and hands each slice to a different node. Ten nodes hold roughly a tenth of the data and take a tenth of the write load each.

One table, split by row

Single DB (users: 400M rows) — one machine, maxed out

Sharded across 4 nodes by user_id:
  shard 0 → users   0M – 100M
  shard 1 → users 100M – 200M
  shard 2 → users 200M – 300M
  shard 3 → users 300M – 400M

Each node stores 1/4 of the rows and serves 1/4 of the writes.

The Core Question

Is your data or write volume genuinely too large for one machine? If a single well-tuned server (with replicas and caching) still copes, don't shard yet — it adds permanent operational complexity. Shard when the data won't fit, the write throughput exceeds one node, or working sets blow past memory.

ARCHITECTURE

Sharding Strategies

Everything comes down to one function: given a row, which shard does it live on? There are four common answers, each with different trade-offs.

Range-based

Split the key space into contiguous ranges (A–F, G–M, …). Great for range scans and easy to reason about — but skewed data or monotonically increasing keys (timestamps, auto-increment IDs) dump everything onto the last shard: an instant hot spot.

Hash-based

Route by hash(key) % N. Spreads rows evenly and kills hot spots from sequential keys. The downside: range queries are scattered across every shard, and changing N reshuffles almost everything (unless you use consistent hashing).

Directory / lookup-based

Keep an explicit lookup table mapping each key (or key range) to a shard. Maximum flexibility — you can move any key anywhere and rebalance surgically — but the directory is a new dependency and a potential single point of failure and bottleneck.

Geo / entity-based

Shard by a natural boundary — region for locality/latency, or tenant/customer so all of one entity's data sits together (keeping most queries single-shard). Risk: uneven entities (one whale tenant) create their own hot shard.

THE BIG DECISION

Choosing a Shard Key

The shard key is the column (or set of columns) you partition on. It is the single most important — and hardest to reverse — decision in a sharded system. A good key has high cardinality, spreads load evenly, and matches how you actually query so most requests hit a single shard.

Good key vs bad key

BAD:  shard by country
  → 60% of users in one country = one shard melts (low cardinality)

BAD:  shard by created_at (increasing)
  → every new write lands on the newest shard = write hot spot

GOOD: shard by user_id (hashed)
  → high cardinality, even spread, and "give me my data"
     queries hit exactly one shard

Hot shards & uneven distribution

When one shard receives a disproportionate share of the traffic, it becomes a hot shard — saturated while its peers sit idle. Causes include low-cardinality keys, a celebrity/whale row, or sequential keys. The fix is a better key (hash a high-cardinality field, add a random suffix, or compound the key), because adding nodes alone won't cool a shard the router keeps overloading.

CHALLENGE

Resharding & Consistent Hashing

Plain hash(key) % N has a nasty property: change N and almost every key remaps to a different shard. Adding a single node can trigger a full data reshuffle across the fleet.

The modulo problem

4 shards → hash(k) % 4
Add one node → hash(k) % 5

key 1001:  %4 = 1   →   %5 = 1    (stayed)
key 1002:  %4 = 2   →   %5 = 2    (stayed)
key 1003:  %4 = 3   →   %5 = 3    (stayed)
key 1004:  %4 = 0   →   %5 = 4    (MOVED)

In practice ~80% of keys move — a massive, disruptive migration.

Consistent hashing

Place both keys and nodes on a hash ring; a key belongs to the next node clockwise. Add or remove a node and only the keys in its arc move — on average 1/N of the data instead of nearly all of it. Virtual nodes (many points per physical node) smooth out the distribution. This is how Cassandra, DynamoDB, and Riak keep resharding cheap when the cluster changes size.

Rebalancing is still painful

Even with consistent hashing, moving data means copying gigabytes between live nodes while serving traffic, keeping source and destination in sync during the cutover, and updating routing without dropping requests. Plan sharding — and headroom — before you desperately need it.

TRADE-OFFS

Cross-Shard Queries & Replication

Sharding is fast when a query touches one shard. It gets expensive the moment a query needs many.

Scatter-gather & joins

A query without the shard key must fan out to every shard (scatter), then merge the results (gather) — as slow as the slowest node. Joins across shards and transactions spanning shards are worse: they need distributed coordination (two-phase commit / sagas), which is slow and failure-prone.

SELECT * FROM orders WHERE user_id = 42;   // 1 shard — fast

SELECT * FROM orders WHERE status = 'refunded';
  // no shard key → ask all N shards, merge → slow

JOIN orders × users across shards
  // data on different nodes → distributed join, avoid if you can

Sharding ≠ Replication (they compose)

Sharding splits different data across nodes to scale capacity and write throughput. Replication copies the same data onto multiple nodes for read scaling and fault tolerance. They are orthogonal and used together: shard for size, then replicate each shard so no single node is a point of failure. A shard with no replicas means losing that node loses that slice of your data.

EXPERIMENT

Live Shard Distribution

WARNING

Sharding Pitfalls

  • →Bad shard key: a low-cardinality or skewed key (country, status, created_at) guarantees hot shards. This is the mistake that's hardest to undo — choose deliberately.
  • →Hot spots: even a good scheme can concentrate load on a celebrity user or whale tenant. Watch per-shard load and plan to split or isolate the outlier.
  • →Cross-shard transactions: distributed commits across shards are slow and fragile. Design so a transaction stays within one shard whenever possible.
  • →Premature sharding: sharding adds permanent complexity. Exhaust vertical scaling, read replicas, and caching before splitting your data across nodes.
  • →Plain modulo hashing: hash(key) % N remaps almost everything when N changes. Use consistent hashing so adding a node only moves ~1/N of the data.
  • →Forgetting replication: a shard without replicas is a single point of failure. Losing that node loses a slice of the dataset — shard and replicate together.
SUMMARY

Key Takeaways

  • →Sharding is horizontal partitioning: split one dataset across many nodes so each holds a subset, scaling capacity and write throughput beyond a single machine.
  • →Only shard when the data or write volume truly exceeds one node — after vertical scaling, replicas, and caching. It adds lasting operational complexity.
  • →Pick from range, hash, directory/lookup, or geo/entity strategies — each trades even distribution against range-query and locality needs.
  • →The shard key is the most important, least reversible decision: high cardinality, even spread, and single-shard queries.
  • →Bad or skewed keys create hot shards — a fix needs a better key, not just more nodes.
  • →Use consistent hashing (with virtual nodes) so adding or removing a node moves only ~1/N of the data instead of nearly all of it.
  • →Cross-shard queries, joins, and transactions are expensive; keep hot-path queries on a single shard.
  • →Sharding and replication are different and complementary — shard for size, replicate each shard for reads and fault tolerance.
REFERENCE

Quick Reference: Sharding Strategies

Range-based

Contiguous key ranges per shard. Excellent for range scans, simple to reason about. Weak to skew and sequential keys → hot shards.

Hash-based

hash(key) % N (ideally consistent hashing). Even distribution, no sequential hot spots. Range queries scatter across all shards.

Directory / lookup

Explicit key→shard map. Maximum flexibility and surgical rebalancing, at the cost of a new dependency and possible bottleneck.

Geo / entity-based

Partition by region or tenant/customer for locality and single-shard queries. Uneven entities (a whale tenant) can still create a hot shard.