The full picture
| Range | Hash | Compound (hash + range) | |
|---|---|---|---|
| Range scans | cheap — one shard | scatter-gather across all | cheap within a partition |
| Write spread | skews to hot ranges | even | even across partitions |
| Rebalancing | split/merge ranges naturally | needs consistent hashing | split by partition key |
| Classic failure | timestamp key → one hot shard | 'get last 100 events' hits every node | cross-partition queries still scatter |
| Seen in | HBase, Bigtable, CockroachDB | Dynamo, Cassandra token ring | Cassandra, DynamoDB, Kafka keys |
- The partition key choice is close to irreversible — it determines every query that can be efficient, and changing it means rewriting the dataset. Treat it as a schema decision made from the query patterns backwards, which is precisely the modelling discipline Cassandra forces and relational habits fight.
- Cardinality is the first sanity check: the number of distinct partition keys must vastly exceed the number of shards, or you cannot spread. Partitioning by
countrywith 3 huge markets, or bystatuswith 5 values, gives you permanent skew no rebalancing can fix. - Time-series is the canonical trap and has a canonical fix: never partition by raw timestamp; bucket it (
deviceId#2026-08orhash(deviceId) + day) so writes spread across devices while a single device's history stays contiguous and scannable. - Hash choice matters more than people expect: use a stable, well-distributed, documented hash (MurmurHash3, xxHash). The hazard is any hash that isn't contractually fixed —
Object.hashCode()is identity-based and differs on every JVM run; Python, Ruby and .NET randomize string hashing per process; enum and record hashes are unspecified. (Java'sString.hashCode()is specified, so it's stable — but it distributes poorly and locks you to one language.) Get this wrong and an upgrade or a restart silently reshuffles the entire keyspace. - Partitioning is orthogonal to replication, and mixing them up is a common confusion: partitioning splits the data (each shard holds a slice), replication copies it (each slice lives on N nodes). Every real system does both — 'shard 7, replicas on nodes 2/5/9' — and saying that sentence clearly disposes of a lot of muddled follow-ups.