Skip to main content

Overview

PostgreSQL supports three partitioning strategies:

Hash Partitioning

Creating a Hash-Partitioned Table

Generating Partitions

Use the pgtofu partition generate command to create partition definitions:
This generates:

Choosing Modulus

Choose your modulus carefully. Changing the number of partitions later requires recreating all partitions and migrating data.

Custom Schema

Range Partitioning

Time-Based Partitioning

Numeric Range Partitioning

List Partitioning

Categorical Data

Partition Management with pgtofu

Workflow

  1. Define parent table with PARTITION BY clause
  2. Generate or write partitions in separate SQL file
  3. Commit to version control
  4. Run pgtofu diff/generate as normal

Partition Validation

pgtofu automatically validates hash partitions when parsing:
  • Checks all REMAINDER values (0 to MODULUS-1) are present
  • Warns about missing partitions
  • Warns about duplicate partitions
Example warning:

Indexes on Partitioned Tables

Global Index (PostgreSQL 11+)

Indexes are inherited by all partitions:

Partition-Specific Indexes

Constraints on Partitions

Primary Keys

Foreign Keys

Foreign keys referencing partitioned tables require PostgreSQL 12+:

Combining with TimescaleDB

For time-series data, consider using TimescaleDB hypertables instead of native range partitioning:
TimescaleDB offers:
  • Automatic chunk creation
  • Built-in compression
  • Continuous aggregates
  • Better query optimization

Best Practices

  • HASH: Use when you need even data distribution and query by partition key
  • RANGE: Use for time-series data or ordered numeric ranges
  • LIST: Use for categorical data with known distinct values
  • Choose columns frequently used in WHERE clauses
  • For HASH: column with high cardinality and frequent equality lookups
  • For RANGE: column with natural ordering (timestamps, sequential IDs)
  • Too few: partitions become too large
  • Too many: query planning overhead increases
  • Sweet spot: 10-100 partitions typically works well
  • Range partitions: create future partitions in advance
  • List partitions: add DEFAULT partition for unknown values
  • Hash partitions: modulus is fixed, plan for growth

Limitations

pgtofu Limitations

  • Only HASH partition generation is automated via CLI
  • RANGE and LIST partitions must be written manually
  • Changing partition strategy requires manual migration

PostgreSQL Limitations

  • Cannot partition an existing table (must create new and migrate)
  • Primary/unique keys must include partition key
  • Some foreign key constraints require PostgreSQL 12+

Troubleshooting

Ensure the partition file is in the --desired directory and uses .sql extension.
Check that all REMAINDER values from 0 to MODULUS-1 are present in your partition definitions.
Ensure your WHERE clause includes the partition key with a literal or parameter.

See Also