Vertical vs Horizontal Partitioning
split by column, or split by rowVertical partitioning splits by column or table โ put rarely-read columns or whole tables on a different store. Horizontal partitioning splits by row โ the same table's rows spread across nodes by some key. Sharding is horizontal partitioning across separate machines, and it's the one that lets you grow past a single node's storage and write capacity.
VERTICAL (by column/table) HORIZONTAL / SHARDING (by row) โโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโ โ id โ name โ big_blob โ โ shard A โ โ shard B โ โ shard C โ โโโโโโผโโโโโโโผโโโโโโโโโโโค โ users โ โ users โ โ users โ โ hot cols โ cold cols โ โ โ 0โ333 โ โ 334โ666 โ โ 667โ999 โ โ on DB-1 โ on DB-2 โ โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโ each node holds a SUBSET of the rows, relieves one table's width on its own machine
Choosing a Shard Key
the single most important decisionThe shard key decides which node each row lives on, and it's the choice you can't easily undo. A good key does two things at once: it distributes evenly so no node is overloaded, and it aligns with the dominant query so most reads hit a single shard.
Get it wrong and you pay the cross-shard query tax: a query that can't be answered from one shard has to fan out to all of them, wait for the slowest, and merge โ turning one lookup into N. Shard a chat app by message ID and "give me this conversation" scatters across every node; shard by conversation ID and it's one node.
Hash vs Range Sharding
even spread, or range queries โ pick oneTwo ways to map a key to a shard, and they trade the exact same thing against each other.
Hash the key and assign by the result. Spreads load beautifully โ even sequential keys land on random shards. The cost: range queries are dead. "All records from last week" is scattered across every shard because adjacent keys hash apart.
Assign contiguous key ranges to shards. Range scans and "give me a window" queries stay on one or two shards. The cost: hot spots on sequential keys โ timestamps or auto-increment IDs pile every new write onto the newest shard.
Consistent Hashing
adding a node without reshuffling everythingNaive hashing โ shard = hash(key) % N โ has a fatal flaw: change N (add or lose a node) and the modulo shifts for almost every key, so nearly all the data has to move. On a live cluster that's catastrophic. Consistent hashing fixes it so a membership change moves only about 1/N of the keys.
Place nodes AND keys on a ring (hash space wrapped into a circle).
Each key belongs to the first node CLOCKWISE from it.
[Node A]
k1 ยท ยท k2
ยท ยท
[Node C] [Node B]
ยท ยท
k4 ยท ยท k3
(ring)
Add Node D between B and C:
only the keys that fall in the BโD arc move (from C to D).
Everything else stays put. โ ~1/N of keys relocate, not all of them.
Problem: with few nodes the ring is lumpy โ some own huge arcs.
Fix: VIRTUAL NODES. Each physical node gets many points on the ring,
so load evens out and a lost node's share spreads across all the others.
Virtual nodes are the practical piece: giving each physical machine many points on the ring smooths the distribution and means when a node dies, its load spreads across all remaining nodes rather than dumping onto its single clockwise neighbor. This is how Cassandra, DynamoDB, and consistent-hash load balancers keep rebalancing cheap (Discovery).
Hot Spots & Rebalancing
when one shard gets all the trafficEven spread of keys doesn't guarantee even spread of traffic. A celebrity's user ID, a viral post, a single hot product โ one key can draw more load than a whole shard can serve. Even distribution assumed uniform access; reality is power-law.
| Problem | Mitigation |
|---|---|
| Celebrity / hot key | Cache it in front so most reads never reach the shard (Caching) |
| Hot key still too heavy | Key salting โ split it into key#1โฆkey#n across shards, merge on read |
| Whole shard overloaded | Split the hot shard, or give the known-hot key dedicated capacity |
| Uneven growth over time | Rebalance: move partitions to new nodes without downtime |
For rebalancing, a fixed number of partitions (many more than nodes) is easier to manage than resharding by hashing: to add a node, you move whole partitions to it, never rehashing individual keys. The data moves in the background while both copies serve, then traffic cuts over โ no downtime.
Unique ID Generation
auto-increment breaks under shardingA single-node auto-increment counter can't span shards โ you'd need every shard to coordinate on the next number, which is exactly the bottleneck sharding was meant to remove. So distributed systems generate IDs differently, and the schemes trade sortability, coordination, and size.
| Scheme | Sortable? | Coordination? | Gotcha |
|---|---|---|---|
| Auto-increment | Yes | Single node | Doesn't scale across shards |
| UUID v4 | No | None | Random โ kills B-tree insert locality |
| UUID v7 | Yes (time-prefixed) | None | Fixes v4's locality problem |
| Snowflake | Yes | Machine ID only | Needs clock sync; 64-bit |
| Ticket server | Yes | Central service | That service is a bottleneck / SPOF |
timestamp | machine ID | per-machine sequence packed into 64 bits. Time-sortable, generated independently on each node with no central coordination, and no collisions as long as machine IDs are unique. When a question needs decentralized, roughly-ordered IDs โ the URL Shortener is the classic โ Snowflake or UUID v7 is the answer (URL Shortener).Quick Reference
sharding and IDs on one card| Hash sharding | Range sharding | |
|---|---|---|
| Distribution | Even | Can be lumpy |
| Range queries | No โ scattered | Yes โ local |
| Hot-spot risk | Low | High on sequential keys |
| Best for | Key-value lookups | Time series, ranges |
| ID scheme | Sortable? | Coordination? | Note |
|---|---|---|---|
| UUID v4 | No | None | Kills insert locality |
| UUID v7 | Yes | None | Time-prefixed, the safe default |
| Snowflake | Yes | Machine ID | Decentralized, needs clock sync |
| Ticket server | Yes | Central | Simple but a bottleneck |