Table partitioning divides a large logical table into smaller physical storage units called partitions, each containing a subset of the rows. From the application's perspective, the partitioned table appears as a single table — queries, inserts, and updates reference the parent table name. Internally, PostgreSQL routes each row to the correct child partition based on the partition key column's value. Partitioning enables three critical performance benefits: partition pruning (queries that filter on the partition key scan only relevant partitions), partition-wise aggregation (parallel computation across partitions), and efficient data lifecycle management (dropping an entire partition is instant, while deleting millions of rows is slow).
PostgreSQL offers three partitioning strategies. Range partitioning assigns rows to partitions based on a range of values on the partition key — typically a date range (one partition per month, one per year). List partitioning assigns rows based on a specific set of discrete values — one partition per country, one per format type. Hash partitioning distributes rows across a fixed number of partitions based on the hash of the partition key — providing even data distribution without natural range or category boundaries. Each strategy is correct for different data distribution patterns and query access patterns.
For data engineers, partitioning is a critical technique for managing very large tables (hundreds of millions to billions of rows) that would be impractical to maintain without it. Time-series fact tables — delivery logs, match events, transaction records — are the most common candidates for range partitioning by date. Dimension tables segmented by region or country benefit from list partitioning. Distributed user activity tables with uniform access patterns benefit from hash partitioning. Designing the correct partitioning strategy at schema creation time is far cheaper than repartitioning after a table has grown to billions of rows.