Partitioning: Range, Hash, List & Composite
Split massive tables into manageable pieces for faster queries and easier maintenance.
๐ฏ What You'll Learn
- Range partitioning for time-series and sequential data
- List partitioning for categorical columns (region, status)
- Hash partitioning for even load distribution
- Partition maintenance: attach, detach, archive, and monitor
- Composite partitioning for multi-dimensional splits
๐ Range Partitioning
Imagine a filing cabinet with drawers labeled by month. When you need March invoices, you open only the March drawer. Range partitioning works the same way โ the database skips irrelevant partitions entirely (called partition pruning).
Range Partitioning
Split by date ranges for time-series data
-- RANGE Partitioning: split by value ranges
-- Best for: time-series data (logs, orders, events)
CREATE TABLE orders (
id BIGSERIAL,
customer_id INT NOT NULL,
order_date DATE NOT NULL,
total DECIMAL(12,2),
status VARCHAR(20)
) PARTITION BY RANGE (order_date);
-- Create partitions for each quarter
CREATE TABLE orders_2024_q1 PARTITION OF orders
FOR VALUES FROM ('2024-01-01') TO ('2024-04-01');
CREATE TABLE orders_2024_q2 PARTITION OF orders
FOR VALUES FROM ('2024-0
...๐ List Partitioning
List partitioning assigns rows to partitions based on exact values โ like sorting mail into bins labeled by country. Perfect for categorical data where you always filter by category.
๐ก Pro Tip โ Always Add a DEFAULT Partition
Without a DEFAULT partition, inserting a row with an unlisted value fails with an error. The DEFAULT partition catches everything that doesn't match any specific partition.
List Partitioning
Split by categorical values like region or type
-- LIST Partitioning: split by specific values
-- Best for: categorical data (regions, status, type)
CREATE TABLE customers (
id SERIAL,
name VARCHAR(100),
email VARCHAR(200),
region VARCHAR(20) NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
) PARTITION BY LIST (region);
CREATE TABLE customers_americas PARTITION OF customers
FOR VALUES IN ('us', 'ca', 'mx', 'br');
CREATE TABLE customers_europe PARTITION OF customers
FOR VALUES IN ('uk', 'de', 'fr', 'es', 'it');
CREA
...#๏ธโฃ Hash Partitioning
When data has no natural range or category, hash partitioning distributes rows evenly using a hash function. Like dealing cards โ each player gets roughly equal hands, but you can't predict which card goes where.
โ ๏ธ Common Mistake
Using hash partitioning when you need range queries. Hash partitions only prune for exact equality (WHERE id = 42). Range queries (WHERE id > 100) must scan all partitions.
Hash Partitioning
Even distribution when no natural split exists
-- HASH Partitioning: even distribution by hash
-- Best for: spreading load when no natural range/list exists
CREATE TABLE sessions (
id UUID DEFAULT gen_random_uuid(),
user_id INT NOT NULL,
data JSONB,
created_at TIMESTAMP DEFAULT NOW()
) PARTITION BY HASH (user_id);
-- Create 4 hash partitions (use power of 2 for even distribution)
CREATE TABLE sessions_p0 PARTITION OF sessions
FOR VALUES WITH (MODULUS 4, REMAINDER 0);
CREATE TABLE sessions_p1 PARTITION OF sessions
FO
...๐ง Partition Maintenance
Partitions need lifecycle management โ adding new partitions for upcoming months, archiving old ones, and monitoring sizes. These operations are typically automated with cron jobs or scheduled procedures.
Partition Maintenance
Add, detach, archive, and monitor partitions
-- Partition Maintenance Operations
-- 1. Add a new partition (e.g., new quarter)
CREATE TABLE orders_2025_q1 PARTITION OF orders
FOR VALUES FROM ('2025-01-01') TO ('2025-04-01');
-- 2. Detach a partition (keep data, remove from parent)
ALTER TABLE orders DETACH PARTITION orders_2024_q1;
-- Now orders_2024_q1 is a standalone table
-- Queries on "orders" no longer include it
-- 3. Archive old data by detaching + moving
ALTER TABLE orders DETACH PARTITION orders_2024_q1;
ALTER TABLE orders_
...๐งฉ Composite Partitioning
For truly massive tables, split on two dimensions: first by date (range), then by category (list) within each date range. Queries that filter on both get double pruning โ scanning only the exact sub-partition needed.
Composite Partitioning
Multi-level partitioning for billions of rows
-- Composite (Sub-) Partitioning
-- Split by range, then by list within each range
CREATE TABLE events (
id BIGSERIAL,
event_type VARCHAR(50) NOT NULL,
event_date DATE NOT NULL,
payload JSONB
) PARTITION BY RANGE (event_date);
-- Year-level partitions, sub-partitioned by type
CREATE TABLE events_2024 PARTITION OF events
FOR VALUES FROM ('2024-01-01') TO ('2025-01-01')
PARTITION BY LIST (event_type);
CREATE TABLE events_2024_clicks PARTITION OF events_2024
FOR VALUE
...๐ Quick Reference
| Type | Best For | Pruning |
|---|---|---|
| RANGE | Dates, sequential IDs | Range + equality |
| LIST | Categories, regions | Equality only |
| HASH | Even distribution | Equality only |
| Composite | 2+ filter dimensions | Multi-level |
๐ Lesson Complete!
You now know how to partition tables for performance and maintainability. Next, explore sharding and distributed SQL!
Sign up for free to track which lessons you've completed and get learning reminders.