We use analytics cookies.We use cookies to analyze site traffic and improve your experience.
Loading...
4 system design questions lean on this idea. Each walks through the full answer.
System Design Masterclass · Database Fundamentals
Free preview: the first 2 parts of this 11-part lesson.
Already bought the course? Sign in to read the whole lesson.
this lesson is part of
System Design Masterclass
Unlock this lesson and the 751 other paid lessons
$25 once, by PayPal
See the System Design courseread the rest of this lesson in
System Design Masterclass
Unlock this lesson and the 751 other paid lessons
$25 once, by PayPal
See the System Design coursein Database Fundamentals
This lesson is part of the full System Design Masterclass. Unlock it along with 769 other lessons for a one-time payment.
One-time payment by card or PayPal
Get Lifetime AccessOne-time payment: UPI, card or netbanking
Get Lifetime Access18 Foundation lessons are free, no payment needed. Try them now
It is easy and good
“It is really nice and good Please join the course”
Range partitioning works beautifully when your data has a time dimension. But what about a users table? There's no natural range. User IDs are random UUIDs. User creation dates are clustered (90% of signups happened in the last 6 months). Country-based partitioning puts 40% of users in one partition.
You need even distribution without relying on the data's natural ordering. You need a mathematical function that takes any input and maps it to a uniformly distributed output.
That's a hash function.
Hash partitioning applies a hash function to the partition key and uses the result to assign each row to a partition. partition_number = hash(user_id) % number_of_partitions. A good hash function guarantees that regardless of the input distribution, sequential IDs, clustered timestamps, skewed categories, the output is approximately uniform.
No hotspots. No skew. Every partition gets roughly the same number of rows.
In PostgreSQL:
CREATE TABLE users (
id UUID DEFAULT gen_random_uuid(),
name VARCHAR(255),
email VARCHAR(255),
created_at TIMESTAMPTZ DEFAULT now()
) PARTITION BY HASH (id);
-- Create 16 partitions
CREATE TABLE users_p0 PARTITION OF users FOR VALUES WITH (MODULUS 16, REMAINDER 0);
CREATE TABLE users_p1 PARTITION OF users FOR VALUES WITH (MODULUS 16, REMAINDER 1);
CREATE TABLE users_p2 PARTITION OF users FOR VALUES WITH (MODULUS 16, REMAINDER 2);
-- ... Up to p15
When you insert a user with id = 'a1b2c3...':
hash('a1b2c3...'), an integerhash_value % 16, the remainder determines the partitionusers_p7)Partition pruning still works, but only for equality queries:
-- Fast: hash(id) directly maps to one partition
SELECT * FROM users WHERE id = 'a1b2c3...';
-- Slow: range scan can't be pruned, must scan all 16 partitions
SELECT * FROM users WHERE created_at >= '2025-01-01';
-- Slow: LIKE can't be hashed, scans all partitions
SELECT * FROM users WHERE name LIKE 'Ron%';
This is the fundamental trade-off of hash partitioning: perfect distribution at the cost of range query performance.