Cloud Tech by Victor
DatabasesIntermediate

Database Partitioning

How range, list, and hash partitioning each split one logical table into physical pieces, and why partition pruning depends entirely on the WHERE clause matching partition bounds directly, not on any index.

Updated 2026-07-243 min read

Overview

Partitioning splits one large logical table into smaller physical pieces using one of three strategies: range (non-overlapping value ranges, natural for time-series data), list (explicit, named value groups), or hash (even distribution by hash modulo a partition count, when there's no natural range or category). The performance payoff is partition pruning: when a query's WHERE clause constrains the partition key with values the planner can compare directly against each partition's declared bounds, entire partitions get eliminated from the plan before execution, not scanned and filtered afterward, a query touching one month of a decade-spanning, monthly-partitioned table can skip well over a hundred partitions entirely. Pruning depends purely on partition bounds, not indexes, but it requires the filter value to be something the planner can actually reason about, a literal or bound parameter, not a volatile expression like CURRENT_TIMESTAMP whose value isn't fixed at plan time.

Quick Reference

StrategySplit byNatural fit
RangeNon-overlapping value rangesTime-series data (logs by month/year)
ListExplicit, named value groupsKnown, finite categories (region, status)
HashHash of key modulo partition countEven distribution, no natural range/category

Syntax

sql
CREATE TABLE measurement (
    city_id   int NOT NULL,
    logdate   date NOT NULL,
    peaktemp  int
) PARTITION BY RANGE (logdate);

CREATE TABLE measurement_y2026m01 PARTITION OF measurement
    FOR VALUES FROM ('2026-01-01') TO ('2026-02-01');

Examples

sql
-- Partition pruning eliminates every partition outside the
-- matching range before execution, not by scanning and filtering.
EXPLAIN SELECT count(*) FROM measurement WHERE logdate >= DATE '2026-01-01';
-- Seq Scan on measurement_y2026m01 only; every earlier
-- monthly partition is pruned entirely.

Volatile expressions defeat plan-time pruning

WHERE logdate >= CURRENT_TIMESTAMP can't be pruned at plan time because the value isn't fixed until the query actually runs. Filter on literals or bound parameters the planner can compare directly against partition bounds, not on non-immutable functions.

Visual Diagram

Common Mistakes

  • Choosing hash partitioning by default when the data actually has a natural range (time) or category (region) that would partition-prune more effectively.
  • Assuming partitioning alone speeds up every query, when pruning specifically requires filtering on the partition key with a value the planner can reason about at plan time.
  • Filtering on a volatile expression like CURRENT_TIMESTAMP or now() and being confused why pruning didn't eliminate any partitions.
  • Not creating a new range partition ahead of when data for it starts arriving, causing inserts to fail or fall into an unintended default partition.

Performance

  • Pruning is driven entirely by partition bounds, not indexes, a partitioned table with no indexes at all still benefits, though indexes still help within whichever partition is actually scanned.
  • Partition pruning can also happen at execution time (for genuinely parameterized values from a join or subquery), visible in EXPLAIN ANALYZE output as (never executed) on eliminated partitions, distinct from plan-time pruning.

Best Practices

  • Choose range partitioning for time-series data, list for known finite categories, and hash only when neither natural split exists.
  • Write filters on the partition key using literals or bound parameters, not volatile expressions, so plan-time pruning can actually apply.
  • Pre-create upcoming range partitions ahead of the data that will need them, rather than reactively after inserts start failing.
  • Verify pruning is actually happening with EXPLAIN, don't assume it based on the table being partitioned at all.

Interview questions

What is the difference between range, list, and hash partitioning, and when would you choose each?

Range partitioning divides rows by a value falling within a bounded, non-overlapping range (inclusive lower bound, exclusive upper bound), the natural fit for time-series data like logs partitioned by month. List partitioning explicitly assigns specific key values to specific partitions, a good fit when data naturally groups into a known, finite set of categories, like a specific list of counties or regions. Hash partitioning distributes rows by the hash of the partition key modulo a chosen number of partitions, useful specifically when there is no natural range or category to split on and you just need to spread rows roughly evenly across a fixed number of partitions.

A query filters WHERE logdate >= 2008-01-01 against a table range-partitioned by logdate across dozens of monthly partitions. What does partition pruning actually do, and what does it depend on?

Partition pruning lets the planner prove, from the query's WHERE clause and each partition's declared bounds, that some partitions cannot possibly contain a matching row, and it excludes them from the plan entirely rather than scanning and filtering every partition. In this example, `logdate >= 2008-01-01` has no upper bound, so it prunes only the partitions entirely before 2008-01, decades of older monthly partitions are eliminated before execution, while every partition from 2008-01 onward, including all of them up to the present, is still considered and scanned. Pruning down to a single partition would need a bounded predicate on both ends, for example `logdate >= 2008-01-01 AND logdate < 2008-02-01`. This depends entirely on the partition bounds themselves, not on any index, a partitioned table with no indexes at all still benefits from pruning, and pruning specifically requires the WHERE clause to reference the partition key directly with values (or parameters) the planner can actually compare against those bounds.

Why can't partition pruning work with a WHERE clause like WHERE logdate >= CURRENT_TIMESTAMP, and what does that tell you about writing partition-friendly queries?

Partition pruning at plan time requires the comparison value to be known and fixed when the plan is built, and `CURRENT_TIMESTAMP` is not immutable, its value depends on when the query actually executes, not when it's planned, so the planner can't statically prove which partitions it will or won't match. (Pruning can still happen at execution time for genuinely parameterized values, like a join parameter from an outer query, just not for volatile functions like this one.) This means writing partition-friendly queries means filtering on the partition key with values the planner can actually reason about, a literal, a bound parameter, or an immutable expression, not a function whose result varies by when the query runs.

References

ShareXLinkedInReddit
Was this page helpful?
Suggest an improvement