Back to the map

Module 08 · Database scaling · Lesson 2 of 9

Partitioning

Splitting one huge table into pieces inside a single database, by range, list or hash. What partitioning buys (pruning, cheap retention, small indexes), what it does not (write capacity), and how it differs from sharding.

IntroShould-knowJunior 9 min Updated Nov 2026

Why it matters

A table with five billion rows is slow to index, slow to vacuum, impossible to delete from efficiently, and its indexes no longer fit in memory. Partitioning splits it into manageable pieces while the application still sees one table. It is the step that keeps a single database useful long after a table has outgrown the naive layout, and it is the step people confuse with sharding, which is a far bigger commitment.

The idea

Partitioning divides a table into physical pieces (partitions) according to a rule on a column, within one database instance. Queries that include the partition column touch only the relevant partitions (pruning); maintenance operates per partition; old partitions are dropped in one metadata operation.

StrategyRuleFitsWatch for
RangeRows fall into ranges of a value: one partition per month of created_atTime-ordered data, retention by age, queries by time windowAll inserts land in the newest partition (fine, but it is the hot one)
ListExplicit values map to partitions: region = 'eu' | 'us' | 'apac'Data with a small set of natural groups; regulatory separationUneven groups; a new value needs a new partition
Hashhash(key) mod N decides the partitionSpreading a large table evenly when there is no natural rangeNo pruning for range queries; changing N means rewriting
CompositeRange then hash, or list then rangeTime-partitioned data that also needs spreadingComplexity; many small partitions
eventsone logical tableevents_2026_09events_2026_10events_2026_11WHERE ts > now() − 7dDROP PARTITION
Range partitioning by month: a query for last week prunes to one partition, and retention drops the oldest partition instantly instead of deleting rows.

What partitioning buys

Pruning: a query with the partition key reads a fraction of the data and uses a fraction-sized index. Cheap retention: dropping a month is instant and leaves no bloat, while deleting a month of rows from an unpartitioned table takes hours and fragments everything. Maintenance locality: vacuum, reindex and statistics run per partition, and the hot partition stays small enough to live in memory. Archival: an old partition can be detached and moved to cheaper storage.

What it does not buy

More write capacity: all partitions live on the same instance, share the same CPU, memory, disk and write-ahead log. Partitioning is about organising data, not about adding machines. When one instance cannot absorb the writes, the answer is replication for reads and sharding for writes, both later in this module.

Pitfalls

Queries that omit the partition key scan every partition, often slower than the unpartitioned table because each partition's index is consulted separately. Unique constraints must include the partition key, which complicates "email must be unique" on a table partitioned by date. Too many partitions (tens of thousands) slow planning. Hash partitioning spreads writes evenly but defeats pruning for ranges, so pick it only when there is no natural range.

Vertical partitioning

A different cut: splitting a wide table's columns into two tables, the hot, small columns in one and the rarely read large ones (a JSON blob, a description) in another, so the hot table stays compact and cache-friendly. Same instance, same data, better locality for the common query.

Trade-offs

Partitioning buys pruning, instant retention and manageable maintenance for very large tables, and pays with constraints on uniqueness, planning overhead and queries that must carry the partition key to benefit. It extends the life of a single database by a lot and adds no capacity for writes, which is both its strength (low risk) and its limit.

In an interview

Distinguish it from sharding out loud: "The events table is range-partitioned by month inside Postgres: queries carry a time range so they prune to one or two partitions, retention drops the oldest partition nightly, and indexes stay small. That is organisation within one instance; if write volume outgrows the instance we shard by tenant across instances, which is a separate step." Interviewers reward the distinction because it is so often blurred.

Check yourself

A team range-partitions a table by month and is surprised that a query filtering only on user_id got slower. Why?

Partitioning · Backplane