Interview Prep Zoneby CuriouserLabs

Question 1 of 5 · senior level

Range vs hash partitioning — how do you choose, and what does each break?

🎤 Say this first

Range partitioning keeps keys in sorted order (shard A = users a–f, B = g–m …), which makes range scans and time-window queries cheap because they touch one or two shards. Its failure mode is skew and hotspots: partition by timestamp and every write goes to the newest shard, turning your cluster into one machine. Hash partitioning applies a hash to the key and distributes by the result, which spreads load beautifully — and destroys ordering, so a range scan becomes a scatter-gather across every shard. The usual production answer is a compound key: hash-partition on a high-cardinality prefix (tenant, user, device) and range-order within the partition — exactly Cassandra's partition key + clustering columns, and DynamoDB's partition key + sort key. You get spread across shards and locality within one.

The full picture

RangeHashCompound (hash + range)
Range scanscheap — one shardscatter-gather across allcheap within a partition
Write spreadskews to hot rangeseveneven across partitions
Rebalancingsplit/merge ranges naturallyneeds consistent hashingsplit by partition key
Classic failuretimestamp key → one hot shard'get last 100 events' hits every nodecross-partition queries still scatter
Seen inHBase, Bigtable, CockroachDBDynamo, Cassandra token ringCassandra, 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 country with 3 huge markets, or by status with 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-08 or hash(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) — never Object.hashCode() or a language's default string hash, which can change between versions or platforms and silently reshuffle the entire keyspace on upgrade.
  • 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.

🔄 Likely follow-up questions

  • You must support both 'latest events globally' and 'events for one device' — how do you partition?
  • Why is Object.hashCode() a hazardous choice for a partition function?
  • How would you migrate a live table to a different partition key?