We use analytics cookies.We use cookies to analyze site traffic and improve your experience.
Loading...
System Design Masterclass · Database Fundamentals
Free preview: the first 2 parts of this 10-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”
Your users table started with 5 columns. Three years later, it has 47. Name, email, password hash, avatar URL, bio, address line 1, address line 2, city, state, zip, country, phone number, preferences (JSON blob), notification settings (another JSON blob), two-factor secret, backup codes, last login time, login count, referral code, subscription tier, Stripe customer ID, Razorpay customer ID, and 25 more.
Every time your application loads a user, it fetches all 47 columns. Even if the page only needs the name and avatar. The row is 4KB. Your buffer pool holds 100,000 pages. Each page is 8KB. That's 800MB of data cache, and half of it is columns you don't need for 95% of queries.
Vertical partitioning splits a table by columns. You take the 5 columns that every query needs (id, name, email, avatar, role) and keep them in one table. The 42 columns that are rarely needed (address, preferences, billing info) go into a separate table.
Same rows. Fewer columns per table. Each table is narrower, fits more rows per page, and uses buffer pool memory more efficiently.
You start with one wide table:
-- Before: one wide table (47 columns, ~4KB per row)
CREATE TABLE users (
id UUID PRIMARY KEY,
name VARCHAR(255),
email VARCHAR(255),
avatar_url TEXT,
role VARCHAR(50),
bio TEXT,
address_line_1 VARCHAR(255),
address_line_2 VARCHAR(255),
city VARCHAR(100),
. ... 38 more columns
);
After vertical partitioning:
-- Hot table: queried on every page load (~200 bytes per row)
CREATE TABLE users_core (
id UUID PRIMARY KEY,
name VARCHAR(255),
email VARCHAR(255),
avatar_url TEXT,
role VARCHAR(50)
);
-- Warm table: queried on profile pages (~500 bytes per row)
CREATE TABLE users_profile (
user_id UUID PRIMARY KEY REFERENCES users_core(id),
bio TEXT,
website VARCHAR(255),
social_links JSONB,
preferences JSONB
);
-- Cold table: queried only in billing/admin flows (~1KB per row)
CREATE TABLE users_billing (
user_id UUID PRIMARY KEY REFERENCES users_core(id),
address_line_1 VARCHAR(255),
address_line_2 VARCHAR(255),
city VARCHAR(100),
state VARCHAR(100),
country VARCHAR(50),
stripe_customer_id VARCHAR(255),
razorpay_customer_id VARCHAR(255)
);
The hot table (users_core) is 200 bytes per row instead of 4KB. That means 40x more rows fit per 8KB page. Your buffer pool now caches 40x more users. Cache hit rate jumps from 60% to 99%.