The Runtime Theory
hardApplicationDSA#sharding#distributed-systems#data-modeling

How do you shard a database and what breaks?

The interviewer is testing whether you understand horizontal partitioning as a last resort — shard key design, what stops working (joins, transactions, uniqueness), and resharding.

The Runtime Theory Team2 min readasked at stripe · amazon · cockroachlabs · datadog

Sharding means splitting one logical table across multiple database nodes, each holding a disjoint subset of rows. It's the last lever: you shard when one node — its CPU, its I/O, its connection count — is saturated and everything cheaper has failed. The interviewer wants to know you understand sharding as a tax on application code, not a scale-up trick.

The only design decision that matters is the shard key: the column the data is partitioned on. Hash partitioning (shard = hash(key) mod N) spreads writes evenly but scatters related rows; range partitioning keeps regions together but creates hot shards. The key must match how you query: every query that filters on the shard key routes to exactly one shard — a scatter query that doesn't touch the key has to fan out to every node and merge results, and that's where the pain lives.

What breaks, concretely. Joins: a join between two tables works only if both are sharded on the same key with co-located rows — otherwise it becomes a scatter-gather across N servers with the merge in your application. Transactions: a transaction touching rows on two shards needs distributed coordination (2PC, which is slow and fragile, or sagas, which aren't transactions) — so the discipline is "one transaction, one shard," which reshapes your schema: orders and their items shard together on customer ID so checkout touches one node. Uniqueness: a unique constraint is now per-shard — two shards can each happily insert the same email — so global uniqueness needs a coordinator or keys designed to embed the shard. IDs: auto-increment counters collide across shards; the fix is snowflake-style IDs (timestamp + machine ID + sequence), which also embed the shard for routing. Secondary indexes: an index on a non-shard-key column doesn't exist globally — queries on it scan every shard, which is why sharded systems add denormalized lookup tables. Resharding: changing N later means rebalancing live traffic — virtual buckets (e.g. 2^16 logical slots mapped to physical shards, as Vitess and Cassandra use) let you move slots without rewriting routing logic.

The operational half: every shard needs its own connection pool, its own replica set, its own failover — your operations surface multiplies by N. And you lose global primitives: ORDER BY over the whole table, global aggregates, and LIMIT semantics all require app-side merge logic.

The answer that closes well is the reframing: the only sharding that doesn't hurt is the one you never need. Design for it — pick the key early, keep transactions single-shard — then defer it until the single node is genuinely the bottleneck. Sharding isn't how you scale; it's what you do when scaling runs out of cheaper options.

This answer walks

Follow-ups they'll push on

  1. 01What makes a good shard key and how do you know it's bad before it's too late?
  2. 02How do you assign a globally unique ID to rows on different shards?
  3. 03What happens to a secondary index when you shard?

More interviews in this topic

One dispatch a week

The trace behind each question, the tradeoff that explains it, and one technical dispatch per week — no noise.

One technical dispatch per week. No noise.