Overview
PostgreSQL supports three partitioning strategies:| Strategy | Use Case | Key Distribution |
|---|---|---|
| HASH | Distribute data evenly | Hash of partition key |
| RANGE | Time-series, ordered data | Value ranges |
| LIST | Categorical data | Explicit value lists |
Hash Partitioning
Creating a Hash-Partitioned Table
Generating Partitions
Use thepgtofu partition generate command to create partition definitions:
Choosing Modulus
| Table Size | Recommended Modulus |
|---|---|
| < 1M rows | 4-8 |
| 1-100M rows | 16-32 |
| 100M-1B rows | 32-64 |
| > 1B rows | 64-128 |
Custom Schema
Range Partitioning
Time-Based Partitioning
Numeric Range Partitioning
List Partitioning
Categorical Data
Partition Management with pgtofu
Workflow
- Define parent table with PARTITION BY clause
- Generate or write partitions in separate SQL file
- Commit to version control
- 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
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:- Automatic chunk creation
- Built-in compression
- Continuous aggregates
- Better query optimization
Best Practices
Choosing a Partitioning Strategy
Choosing a Partitioning Strategy
- 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
Partition Key Selection
Partition Key Selection
- 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)
Number of Partitions
Number of Partitions
- Too few: partitions become too large
- Too many: query planning overhead increases
- Sweet spot: 10-100 partitions typically works well
Maintenance
Maintenance
- 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
Partition not detected
Partition not detected
Ensure the partition file is in the
--desired directory and uses .sql extension.Validation warnings
Validation warnings
Check that all REMAINDER values from 0 to MODULUS-1 are present in your partition definitions.
Query not using partition pruning
Query not using partition pruning
Ensure your WHERE clause includes the partition key with a literal or parameter.
See Also
partitioncommand - CLI reference for partition generation- PostgreSQL Features - All PostgreSQL support
- TimescaleDB Features - Automatic time-based partitioning