All Products
Search
Document Center

:pg_partman (partition manager)

Last Updated:Jan 07, 2026

When data tables in PolarDB for PostgreSQL (Compatible with Oracle) grow, manually managing partitioned tables becomes complex and time-consuming. pg_partman is a PostgreSQL extension that addresses this issue by automating partition management. The extension automatically creates and maintains table partitions based on time or serial IDs and enforces data retention policies. This simplifies the lifecycle management of partitioned tables, which improves database maintainability and query performance.

Applicability

Supported versions of PolarDB for PostgreSQL (Compatible with Oracle): Oracle syntax compatibility 2.0 with minor engine version 2.0.14.19.40.0 or later.

Note

You can view the minor engine version in the console or by running the SHOW polardb_version; statement. If your version does not meet the requirements, you must upgrade the minor engine version.

Features

The core feature of the pg_partman extension is the automated management of partitioned tables based on time or numeric/ID values. It is based entirely on the built-in declarative partitioning feature of PostgreSQL (since pg_partman version 5.0.1) and no longer uses the legacy trigger-based method.

The working mechanism is as follows:

  • Automatic partition creation: A background maintenance task pre-creates future partitions based on a set interval, such as daily, monthly, or every 1 million IDs. This ensures that new data can be written seamlessly.

  • Data retention policy: Automatically detaches (DETACH) or drops (DROP) expired data partitions. This manages the data lifecycle and storage costs.

  • Default partition: Creates a default partition for each partition set to catch any data that does not belong to an existing child partition. This prevents data loss. You can use associated functions to migrate this data to the correct partitions.

  • Subpartitioning support: Supports multi-level partitioning. For example, you can subdivide annual partitions into daily partitions to meet complex data organization needs.

Quick start

This section provides a complete example of how to partition a log table by day to help you get started with pg_partman. In this example, you will create a log table named log_table, create a new partition daily based on the created_at field, and configure a policy to automatically delete data that is older than seven days.

Step 1: Install the extension and create a parent table

First, install the pg_partman extension in your database. Then, create a parent table for partitioning.

-- 1. Enable the pg_partman extension in the current database.
CREATE EXTENSION pg_partman;

-- 2. Create a parent table to store log data.
-- PARTITION BY RANGE (created_at) specifies that this table will be a partitioned table,
-- using the created_at column for range partitioning.
CREATE TABLE public.log_table (
    id bigint GENERATED BY DEFAULT AS IDENTITY,
    created_at timestamptz NOT NULL,
    message text
) PARTITION BY RANGE (created_at);

Step 2: Initialize the partition set

Call the create_parent() function to register log_table with the pg_partman management system and define the partitioning rules.

-- Call the create_parent function to initialize partitioning.
-- public.log_table: The parent table to manage.
-- created_at: The partition key column.
-- '1 day': The partition interval, which means a new partition is created daily.
SELECT create_parent(
    p_parent_table := 'public.log_table',
    p_control := 'created_at',
    p_interval := '1 day'
);

After successful execution, pg_partman automatically creates partitions for the current day and the next few days. You can run the \d+ public.log_table command to view the created partitions.

Step 3: Insert test data

Insert some data into the parent table log_table. The data is automatically routed to the corresponding partition based on the created_at value.

INSERT INTO public.log_table (created_at, message)
SELECT generate_series(
     now() - interval '4 days',
     now(),
     interval '1 hour'
 ),
 'This is a log message.';

Step 4: Configure a retention policy and verify cleanup

Set a data retention policy so that pg_partman automatically cleans up expired data. Configure log_table to retain data for the last two days and automatically DROP expired partitions.

-- 1. Update the part_config table to set a retention policy for log_table.
UPDATE part_config
SET
    retention = '2 days',             -- Set the retention period to 2 days.
    retention_keep_table = false      -- Do not keep the table structure. Directly DROP expired partitions.
WHERE parent_table = 'public.log_table';

-- 2. Manually run the maintenance task to trigger the retention policy.
CALL run_maintenance_proc();

-- 3. Verification: Check the partition list again to confirm that partitions older than 2 days have been deleted.
SELECT partition_schemaname, partition_tablename FROM show_partitions('public.log_table', 'DESC');

At this point, you have successfully configured a log table that is partitioned daily and cleaned up automatically.

Precautions

Before you use pg_partman, understand the following limitations and risks to avoid data loss or service interruptions.

  • Attribute inheritance: pg_partman uses a template table to manage some properties that cannot be directly inherited from the parent table, such as specific indexes or the UNLOGGED status. Changes to the template table affect only newly created partitions. Existing partitions must be updated manually.

  • Time zones: When you partition based on time, ensure that the database system, clients, and all environments that call maintenance tasks use a consistent time zone. We recommend that you use UTC to avoid partition creation failures or skips due to issues such as daylight saving time (DST).

  • Subpartitioning:

    • The main function of subpartitioning is data organization and lifecycle management. Its effect on performance improvement is limited. If you want to optimize performance, we recommend that you adjust the partition interval instead of relying on subpartitioning. Too many subpartitions increase management overhead and may exhaust max_locks_per_transaction resources.

    • Subpartitioning does not support logical replication (PUBLICATION/SUBSCRIPTION). If you plan to use logical replication on a partitioned table, avoid using the subpartitioning feature.

    • Subpartition creation (create_sub_parent) is a destructive operation. It deletes and rebuilds existing partitions to add the next level of partitioning. Before execution, we recommend that you back up the relevant data.

  • Object name length: PostgreSQL object names are limited to 63 bytes. pg_partman automatically truncates table names to accommodate suffixes. However, if parent table names are too long and similar, it may cause partition name conflicts across different partition sets. We recommend that you keep parent table names concise.

  • UNIQUE constraints: You cannot create global unique constraints or primary keys on columns other than the partition key. This is a native limitation of PostgreSQL declarative partitioning. pg_partman lets you create local unique constraints on each partition, but this does not guarantee global uniqueness across the entire partition set.

  • Default partition: Data that falls into the default partition must be handled with care. pg_partman creates a default partition to receive data that does not belong to any existing partition. By default, partition maintenance does not check the data in the default partition to create new partitions. If data is continuously written to the default partition, use the partition_data_* series of functions to migrate it to the correct partition as soon as possible. Also, investigate the cause of the abnormal data writes.

  • Undoing partitioning: Executing undo_partition() pauses all partition maintenance. Until the undo operation is complete, run_maintenance() will not create new partitions or enforce retention policies for that partition set.

  • Locks and resources: Managing many partitions can increase lock resource consumption. If a single partition set contains hundreds or thousands of partitions, run_maintenance() or other maintenance operations may require you to adjust the max_locks_per_transaction parameter to avoid running out of memory. In this situation, we recommend that you use the run_maintenance_proc() procedure. It commits the transaction after it maintains each partition set, which reduces lock contention from long-running transactions.

Best practices

Scenario 1: Daily partitioned log table with automatic cleanup

This scenario is suitable for data that grows rapidly and has a clear lifecycle, such as logs, audit records, and Internet of Things (IoT) time series data.

Business scenario

Partition the audit_logs table daily, retain data for 30 days, and automatically archive expired data to another schema instead of deleting it directly.

Procedure

  1. Create a parent table and initialize the partition set:

    -- Create the parent table.
    CREATE TABLE public.audit_logs (
        log_id uuid NOT NULL,
        event_time timestamptz NOT NULL,
        user_id text,
        details jsonb,
        PRIMARY KEY (event_time, log_id)
    ) PARTITION BY RANGE (event_time);
    
    -- Initialize the partition set for daily partitioning.
    SELECT create_parent(
        p_parent_table := 'public.audit_logs',
        p_control := 'event_time',
        p_interval := '1 day'
    );
  2. Configure the retention and archiving policy: Move old partitions that are older than 30 days to the archive schema for subsequent batch analytics or backup.

    -- Create a schema for archiving.
    CREATE SCHEMA IF NOT EXISTS archive;
    
    -- Update the configuration to set the retention policy.
    UPDATE part_config
    SET
        retention = '30 days',          -- Retain for 30 days.
        retention_schema = 'archive'    -- Move to the archive schema after expiration.
    WHERE parent_table = 'public.audit_logs';

    When run_maintenance() runs, any partition table that is entirely older than 30 days, such as audit_logs_p2023_10_01, will be detached from the primary partition set. Its schema will be changed from public to archive, becoming archive.audit_logs_p2023_10_01.

Scenario 2: Business table partitioned by ID

This scenario is suitable for businesses that use a numeric ID as a primary key, such as for user or product tables, and want to separate hot and cold data through partitioning.

Business scenario

Partition the orders table by order_id, with each partition containing 10 million IDs.

Decision advice

The choice of p_interval is critical. You can estimate it based on the growth rate of your business IDs and a reasonable size for a single partition. If 1 million new orders are added daily, an interval of 10000000 means a new partition is created approximately every 10 days.

Procedure

  1. Create a parent table and initialize the partition set:

    -- Create the parent table.
    CREATE TABLE public.orders (
        order_id bigint NOT NULL,
        customer_id bigint,
        order_date timestamptz,
        amount numeric
    ) PARTITION BY RANGE (order_id);
    
    -- Initialize the partition set for partitioning by ID range.
    -- Note: p_interval must be provided as text, even if it is a number.
    SELECT create_parent(
        p_parent_table := 'public.orders',
        p_control := 'order_id',
        p_interval := '10000000' -- Each partition contains 10 million IDs.
    );
  2. Configure a retention policy (optional): If old order data can be archived or deleted, you can configure an ID-based retention policy.

    -- Retain the most recent 50 million order records.
    -- Assume the current maximum order_id is 100,000,000.
    -- This policy will delete all partitions where order_id < 50,000,000.
    UPDATE part_config
    SET
        retention = '50000000',
        retention_keep_table = false
    WHERE parent_table = 'public.orders';

Scenario 3: Migrating a large existing table to a partitioned table

This scenario is for smoothly migrating a large, existing monolithic table, such as a terabyte-scale table, to a partitioned structure managed by pg_partman.

Business scenario

Migrate a 1 TB sensor_data table to a monthly partitioned table and minimize the impact on online services.

Core tool

The partition_data_proc() procedure. It can migrate data in small batches and independent transactions, which avoids long-running table locks and transaction backlogs.

Procedure

  1. Preparations: Create a parent table and initialize the partition set:

    -- 1. Rename the original table to serve as the data source.
    ALTER TABLE public.sensor_data RENAME TO sensor_data_source;
    
    -- 2. Create a new parent table with the same structure.
    CREATE TABLE public.sensor_data (
        reading_id bigserial,
        device_id text,
        ts timestamptz NOT NULL,
        value double precision
    ) PARTITION BY RANGE (ts);
    
    -- 3. Initialize the partition set.
    SELECT create_parent('public.sensor_data','ts','1 month');
  2. Execute data migration: Use partition_data_proc to migrate data in batches from sensor_data_source to the new partitioned table sensor_data.

    -- Call the data migration procedure.
    -- p_source_table: Specifies the source table.
    -- p_interval: The time range of data to process in each batch. We recommend setting it to be less than or equal to the partition interval. Here it is set to '1 day', meaning data for each day is processed in one transaction.
    -- p_wait: The waiting time (in seconds) between each batch, used to reduce sustained pressure on I/O and CPU.
    CALL partition_data_proc(
        p_parent_table := 'public.sensor_data',
        p_source_table := 'public.sensor_data_source',
        p_interval := '1 day',
        p_wait := 1
    );

    This procedure will loop until all data in the sensor_data_source table has been migrated. During the migration, pg_partman will automatically create the required partitions as needed.

  3. Final steps: After the migration is complete, verify data consistency. Then, you can safely delete the original data source table sensor_data_source. During the migration, the application can continue to write new data to the new partitioned parent table sensor_data.

Core concepts

Partition type and interval

Partition type

pg_partman is based on PostgreSQL's declarative partitioning and mainly supports the following partitioning methods:

  • Range Partitioning: Suitable for continuous data, such as timestamps or serial IDs. This is the most common partition type.

  • List Partitioning: Supported only for ID-based partitioning with an interval of 1.

Partition interval (p_interval)

This parameter defines the data range covered by each child partition.

  • Time-based: Accepts any valid interval value, such as '1 hour', '1 day', '1 week', or '1 month'.

    Note
    • The minimum supported time interval is 1 second. The upper limit is constrained by the minimum and maximum timestamp values supported by PostgreSQL.

    • When you first run create_parent() to create a partition set, intervals of less than one day are rounded down when the first partition to create is determined.

      • Intervals less than 24 hours but greater than 1 minute are rounded down to the nearest hour.

      • Intervals less than 1 minute are rounded down to the nearest minute.

      • The system creates enough partitions to support the current real time. This means that when you run create_parent(), more previous partitions may be created than expected, and not all future partitions may be created. The first run of run_maintenance() will create the missing future partitions. This is due to the need to support custom time intervals. For intervals of 24 hours or more, the setup will proceed as expected.

    • For intervals of 100 years or more, the extension will use the actual starting point of the century or millennium to determine partition names and constraint rules. For example, the 21st century and the 3rd millennium started on January 1, 2001 (not 2000). This also means there is no year 0.

  • Numeric/ID-based: Accepts an integer that represents the range size, but it must be provided as text, such as '1000000'.

Note
  • Weekly partitioning: The start day of the week depends on the p_start_partition parameter or the current date when create_parent() is executed. To ensure Monday is the start day, we recommend that you explicitly specify it with the date_trunc() function, for example: p_start_partition := to_char(date_trunc('week', CURRENT_TIMESTAMP), 'YYYY-MM-DD HH24:MI:SS').

  • Epoch time values: If the partition key is an integer column that stores a Unix epoch, you can set the p_epoch parameter, such as 'seconds' or 'milliseconds', so that pg_partman manages it as time-based partitioning.

Sub-partitioning

Subpartitioning lets you create finer-grained partitions on existing partitions to form a multi-level partition structure, such as partitioning by year and then subpartitioning each year by month. It is mainly used for data organization and lifecycle management, such as archiving a large annual partition on a monthly basis. For performance improvement, subpartitioning is usually of limited effectiveness. We recommend that you prioritize the adjustment of the top-level partition interval.

Important

Subpartition creation (create_sub_parent) is a destructive operation. It deletes and rebuilds existing partitions to add the next level of partitioning. Before execution, we recommend that you back up the relevant data.

Data retention policy

pg_partman automatically enforces data retention policies through run_maintenance() to manage the lifecycle of old partitions. The core configuration parameters are as follows:

Parameter

Description

Example

retention

The retention period.

  • Time-based partitioning: An interval value. Any partition containing only data older than this time will be dropped.

  • Numeric/ID partitioning: An integer. Any partition with a numeric/ID value less than the current maximum ID minus the retention value will be dropped. For example, if the current maximum numeric/ID is 100 and the retention value is 30, all partitions with numeric/ID values less than 70 will be dropped. The drop function always uses the current maximum numeric/ID value when it runs.

  • '30 days'

  • '50000000'

retention_keep_table

  • true (default): Detaches (DETACH) the old partition, making it a standalone table.

  • false: Directly drops (DROP) the old partition.

false

retention_schema

Moves the detached old partition to a specified archive schema instead of keeping it in the original schema or dropping it. This setting takes precedence over retention_keep_table.

'archive'

retention_keep_index

Whether to keep the indexes on an old partition when it is detached. The default is true.

true

Important

For subpartition sets, when a partition of a parent table is dropped, if that partition is itself a partitioned table, the drop operation will cascade (CASCADE) to all lower-level partitions in the entire inheritance tree and delete them all. Also note that a partition set managed by pg_partman must always retain at least one partition. Therefore, the retention policy will never drop the last partition in a partition set.

Constraint exclusion

Constraint exclusion is a key feature for improving the query performance of partitioned tables. When the WHERE clause of a query can explicitly exclude certain partitions, the query optimizer will skip scanning those partitions.

pg_partman provides the ability to add CHECK constraints on non-partition key columns to enhance the effect of constraint exclusion. For example, for a table partitioned by created_at, if there are frequent queries with WHERE device_id = 'A', you can add a constraint to the device_id column of old partitions where data no longer changes.

The core configuration parameters are as follows:

  • constraint_cols: A text array that specifies on which columns to create CHECK constraints. For example, '{device_id, user_id}'.

  • optimize_constraint: An integer that defines how old a partition must be before the constraint is applied. The default value of 30 means the constraint is applied to partitions older than 30 partition intervals.

  • constraint_valid: Adding a constraint to a table may conflict with existing data in the table and may also cause pg_partman's maintenance operations to take a long time. You can set these constraints to be not valid when they are created. Although this allows the constraint creation to be almost instantaneous, constraint exclusion cannot be used until it is validated. Therefore, by default, constraints are created as valid.

Note
  • This feature restricts data updates on old partitions where constraints have been added. To modify old data, and to allow pg_partman to manage these constraints correctly, do not rename the constraints it manages. You can use reapply_constraints_proc() to temporarily remove the constraints.

  • constraint_valid may not work correctly in sub-partitioning. It can execute normally on the first level of partitions, but whether it is effective in deeper sub-partitioned table sets depends on the combination of partition intervals used and the setting of optimize_constraint. For example, when a weekly partition is further subdivided into daily partitions, and the daily partition's optimize_constraint is set to 7 days, it may not achieve the expected effect. Although the weekly partition's constraints can be created correctly, the daily subpartitions may not have corresponding constraints created.

Template table and attribute inheritance

Because PostgreSQL declarative partitioning has incomplete support for inheriting certain object attributes, such as primary keys or unique indexes on non-partition keys and autovacuum settings, pg_partman uses a template table mechanism to ensure that newly created partitions can correctly inherit these attributes. The following table shows how pg_partman manages the inheritance of specific attributes. If an attribute is not listed in the table, it is managed through the parent table.

Attribute

Inherited from parent

Inherited from template

Primary key on non-partition columns

-

and later

Unique index on non-partition columns

-

and later

Tablespace for unique index on non-partition columns

-

and later

Relation-specific options (autovacuum, etc.)

-

and later

UNLOGGED table status*

-

and later

Non-unique indexes

and later

-

Permissions/Ownership

and later

-

  • Attributes: When you call create_parent(), pg_partman automatically creates a table named parent_table_template. Any ALTER TABLE modifications you make to this template table, such as adding indexes or changing autovacuum parameters, will be applied when new partitions are created in the future.

    Note

    Modifications to the template table are not retroactively applied to existing partitions. To make changes, you must manually run ALTER operations on the old partitions.

  • Permissions and ownership: By default, permissions and ownership are not inherited. If you enable this feature through pg_partman, note that this inheritance occurs only at partition creation time and is not automatically applied after changes. You can reapply them with reapply_privileges(). You usually do not need to enable this feature unless you need to access partitions directly. If you do, you can set the inherit_privileges option.

    Note

    If you use the IDENTITY feature to manage sequences, it supports automatic generation of new sequence values only when data is inserted through the parent table. It is not supported when you insert data directly into partitions.

Note
  • The template table feature is a temporary solution designed to accelerate the adoption of declarative partitioning. As PostgreSQL core features improve, pg_partman will gradually phase out the use of template tables. If a feature is supported in PostgreSQL core in the future, it will no longer be managed through the template table. You must plan for related adjustments when you upgrade to a major version.

  • If you want to use the REPLICA IDENTITY attribute with the USING INDEX clause to support logical replication, note that this feature is supported only if the required index is created on the actual parent table, not on the template table. Because you cannot control the REPLICA IDENTITY settings on the parent and template tables, it is impossible to determine which is the correct identity. To maintain consistency with other identity inheritance methods (FULL and NONE), we recommend that you select only the parent table as the source.

  • PostgreSQL handles the UNLOGGED attribute inconsistently on the parent table of a partition set. Therefore, pg_partman uses a template table to manage the UNLOGGED status. When an ALTER command is executed, the attribute on the parent table does not actually change, so new partitions continue to use the attribute from before the change. This means that you cannot change a partition set from UNLOGGED to LOGGED and have all future partitions inherit this change. Because this attribute is managed through the template table, changing the attribute on the template table causes newly created partitions to inherit the change. However, you must still change existing partitions manually. For more information, see Unable to alter partitioned table to set logged.

O&M and management

Automatic maintenance

The core maintenance tasks of pg_partman, creating new partitions and enforcing retention policies, are performed by the run_maintenance() function or the run_maintenance_proc() procedure. In PolarDB for PostgreSQL (Compatible with Oracle), we recommend that you use the built-in Background Worker to automate this process. It automatically calls run_maintenance_proc() at the interval you set.

Note

The Background Worker is disabled by default. To enable it, go to Quota Center, find the quota ID polardb_pg_pg_cron, and in the Actions column, click Apply to request the quota.

Manual maintenance

In some cases, you may need to trigger maintenance manually, such as when you are debugging or when you need fine-grained control over a specific table.

  • CALL run_maintenance_proc(); We recommend that you use this procedure. It performs maintenance for all partition sets in part_config where automatic_maintenance is on. It also automatically commits the transaction after each partition set is maintained, which reduces lock contention.

  • SELECT run_maintenance('public.my_table'); If you want to perform maintenance only on a single partition set, you can call this function and pass the parent table name.

Monitoring and alerting

In a production environment, you need to monitor whether partition maintenance is running normally to prevent data write failures caused by partitions not being created in time. The maintenance_last_run field in the part_config table records the timestamp of the last successful maintenance run for each partition set. This is a key monitoring metric.

-- Query for all automatically maintained partition sets that have not run successfully
-- for more than twice the maintenance interval.
SELECT parent_table
FROM part_config
WHERE
    automatic_maintenance = 'on'
    AND maintenance_last_run < (now() - (SELECT setting::interval * 2 FROM pg_settings WHERE name = 'pg_partman_bgw.interval'));

If this query returns any rows, it means that the maintenance for the corresponding partition set may have been interrupted and requires immediate investigation.

Reference functions

pg_partman provides its core capabilities through a series of functions. These functions are divided into four main categories based on their purpose: creation, migration, maintenance, and destruction.

Create partitions

These functions are used to initialize partition sets and define subpartitions.

create_parent()

This function initializes a partition set. It configures the partitioning policy, pre-creation rules, and maintenance method for an existing parent table that has been declared as partitioned. It places an ACCESS EXCLUSIVE lock on the parent table during its run.

Note
  • All options passed to this function must be configured correctly. You must apply all defaults, indexes, constraints, permissions, and ownership to the parent table so that they propagate to the child tables. For instructions on how to handle unique indexes and other table properties, see Template table and attribute inheritance.

  • By default, a default partition and a template table are created, unless otherwise configured.

Syntax
create_parent(
    p_parent_table text
    , p_control text
    , p_interval text
    , p_type text DEFAULT 'range'
    , p_epoch text DEFAULT 'none'
    , p_premake int DEFAULT 4
    , p_start_partition text DEFAULT NULL
    , p_default_table boolean DEFAULT true
    , p_automatic_maintenance text DEFAULT 'on'
    , p_constraint_cols text[] DEFAULT NULL
    , p_template_table text DEFAULT NULL
    , p_jobmon boolean DEFAULT true
    , p_date_trunc_interval text DEFAULT NULL
    , p_control_not_null boolean DEFAULT true
    , p_time_encoder text DEFAULT NULL
    , p_time_decoder text DEFAULT NULL
)
RETURNS boolean
Parameters

Parameter

Type

Required

Default

Description

p_parent_table

text

Yes

None

The parent table of the partition set. Must be an existing, partitioned table, and must include the schema name.

p_control

text

Yes

None

The control column used for partitioning, such as created_at. Supports time, integer, text, or uuid types.

Note

When the control column is of type text or uuid, you must set p_time_encoder and p_time_decoder.

p_interval

text

Yes

None

The partition interval. The parameter value should be passed as text. Valid values are:

  • Time-based partitioning: An interval value, such as '1 day'.

  • Numeric/ID partitioning: An integer range, such as '100000'.

    Note

    If the interval value is greater than or equal to '2', p_type must be range. If the interval is equal to '1', p_type must be list.

p_type

text

No

'range'

The partition type. Valid values are:

  • 'range': Range.

  • 'list': List.

p_epoch

text

No

'none'

Used when the partition key column is an integer representing time (epoch). Valid values are:

  • 'none'

  • 'seconds'

  • 'milliseconds'

  • 'microseconds'

  • 'nanoseconds'

Note

All table names will be based on time. In addition to creating a regular index on the control column, ensure you also create a time-based function-based index on the control column, such as to_timestamp(control_column), for efficient operation.

p_premake

int

No

4

The number of partitions to create in advance. For example, for daily partitioning, 4 means that partitions for the next four days are always maintained.

Note

Certain intervals may occasionally cause an extra partition to be created or one to be missed due to leap years, different month lengths, etc. This usually does not cause problems and should correct itself automatically. For more information, see Partition type and interval. If partitioning falls behind the value of p_premake, running run_maintenance() and inserting data will automatically catch up.

p_start_partition

text

No

NULL

Lets you manually specify the starting value (timestamp or integer) for the first partition, instead of having it determined automatically by the system. Must be a valid timestamp (for time-based partitioning) or a positive integer (for numeric/ID-based partitioning) value.

Note
  • The actual parameter type is text.

    • For time-based partitioning, all partitions from the given timestamp up to CURRENT_TIMESTAMP (plus p_premake) will be created.

    • For numeric/ID-based partitioning, only the partition starting from the given value (plus p_premake) will be created.

  • For subpartitioning, this only applies to the initial setup, not to subsequent maintenance.

p_default_table

boolean

No

true

Whether to create a default partition for the partition set to receive data that does not belong to any child partition.

p_automatic_maintenance

text

No

'on'

Whether this partition set is automatically maintained by the global run_maintenance().

  • 'on'

  • 'off': When set to 'off', you can still call run_maintenance() by passing the partition set as a parameter.

p_constraint_cols

text[]

No

NULL

An array of column names for which to add extra CHECK constraints on old partitions to optimize query performance on non-partition key columns. For more information, see Constraint exclusion.

p_template_table

text

No

NULL

Specifies a template table. Newly created partitions will inherit properties, such as indexes and constraints, from this template. If not specified, one will be created automatically.

p_date_trunc_interval

text

No

NULL

Used to align partition boundaries for non-standard time intervals. Valid values are the interval values accepted by the built-in PostgreSQL date_trunc() function, such as 'day', 'week', 'month', etc.

By default, pg_partman's time-based partitioning truncates the starting value of partitions to typical boundaries, such as midnight for daily, the 1st for monthly, and January 1st for yearly. If you want to use a partition interval that does not fall on these boundaries, you may need this option to ensure that child tables have the expected boundaries, especially if p_start_partition is set.

For example, if you set a 9-week interval, by default pg_partman will truncate the table by month, because the interval is greater than one month but less than one year, which in some cases unexpectedly starts from the first day of the month. Set this parameter to week so that the starting value of the child tables is correctly truncated by week to align with the 9-week interval. If you use a custom time interval, try this option to get the desired partition set, or use a more typical partition interval to simplify partition management.

p_control_not_null

boolean

No

true

Whether the partition control column is required to be NOT NULL.

  • true: The control column must be set to NOT NULL.

  • false: Allows the control column to be set to NULL. Unless there is a clear use case and it has been carefully reviewed, we do not recommend allowing this setting, as it may lead to excessive data in the default child partition.

p_time_encoder

text

No

NULL

When the partition key is of type text/uuid, this is the name of the function used to encode a timestamp into a string. Setting this parameter implicitly enables time-based partitioning. This allows partitioning by time-based identifiers such as uuidv7, ulid, snowflake id, etc. The function must handle NULL input safely.

p_time_decoder

text

No

NULL

When the partition key is of type text/uuid, this is the name of the function used to decode a timestamp into a string. Setting this parameter implicitly enables time-based partitioning. This allows partitioning by time-based identifiers such as uuidv7, ulid, snowflake id, etc. The function must handle NULL input safely.

create_sub_parent()

This function creates a subpartition for an existing partition set. This is a destructive operation because it requires deleting and rebuilding existing partitions to transform them into new parent tables.

Note
  • If you plan to rely on table names for organization, we recommend that you use shorter table names for subpartition sets. The suffix appended to the end of the table name is always guaranteed to exist, regardless of the partition type used by that partition set. Longer table names may cause the original parent table name to be truncated and may also truncate the top-level partition suffix. This truncation is automatic and ensures that the lowest-level partition suffix is preserved.

  • For the first level of subpartitioning, the p_parent_table parameter value you initially passed to create_parent() should be exactly the same as the value passed to create_sub_parent(). To subpartition further, you should start passing different values to create_sub_parent(), that is, the child tables of the top-level partition set.

Syntax
create_sub_parent(
    p_top_parent text
    , p_control text
    , p_interval text
    , p_type text DEFAULT 'range'
    , p_default_table boolean DEFAULT true
    , p_declarative_check text DEFAULT NULL
    , p_constraint_cols text[] DEFAULT NULL
    , p_premake int DEFAULT 4
    , p_start_partition text DEFAULT NULL
    , p_epoch text DEFAULT 'none'
    , p_jobmon boolean DEFAULT true
    , p_date_trunc_interval text DEFAULT NULL
    , p_control_not_null boolean DEFAULT true
    , p_time_encoder text DEFAULT NULL
    , p_time_decoder text DEFAULT NULL
)
RETURNS boolean
Parameters

Parameter

Type

Required

Default

Description

p_top_parent

text

Yes

None

The name of the top-level parent table. This function will transform all partitions under this parent table into new subpartition parent tables.

p_declarative_check

text

Yes

NULL

A safety confirmation flag. Must be set to 'yes' to proceed. This is to ensure you are aware of and consent to this destructive operation, which will clear the partition data.

The remaining parameters, such as p_control or p_interval, have the same function as in create_parent(), but they define the policy for the subpartitions. For example, if you have an existing partition set partitioned by year and then want to partition each year partition by day, you can use this function.

create_partition_time()/create_partition_id()

Manually create specific child partitions for time-based or numeric/ID-based partition sets. This is usually called automatically by run_maintenance(), but can also be used to create partitions on demand outside of the maintenance cycle.

Syntax
create_partition_time(
    p_parent_table text
    , p_partition_times timestamptz[]
    , p_start_partition text DEFAULT NULL
)
RETURNS boolean

create_partition_id(
    p_parent_table text
    , p_partition_ids bigint[]
    , p_start_partition text DEFAULT NULL
)
RETURNS boolean
Parameters

Parameter

Type

Required

Default

Description

p_parent_table

text

Yes

None

The parent table for which to create child partitions.

p_partition_times

timestamptz[]

Yes

None

An array of timestamptz values, where each value represents the lower bound of a time partition to be created.

If the partition does not exist, it will be created. If it exists, the existing partition is used and the function will still exit normally. Note that the given value will be used as the lower bound of the partition and will affect the partition's name. Therefore, ensure that the given timestamp value is consistent with other partitions, otherwise you may encounter gaps with value overlaps.

p_partition_ids

bigint[]

Yes

None

An array of bigint values, where each value represents the lower bound of an ID partition to be created.

If the partition does not exist, it will be created. If it exists, the existing partition is used and the function will still exit normally. Note that the given value will be used as the lower bound of the partition and will affect the partition's name. Therefore, ensure that the given integer value is consistent with other partitions, otherwise you may encounter gaps with value overlaps.

p_start_partition

text

No

NULL

Used in subpartitioning scenarios to specify the starting value of a subpartition.

Migrate data

These functions are used to migrate historical data or data that has mistakenly entered a default partition into the correct partitions.

partition_data_time()/partition_data_id()

Migrates data from a parent table, default partition, or a specified source table into the corresponding partitions. If the target partition does not exist, the function automatically creates it. It can also fix data that has been inserted into the default table.

Note
  • To automatically partition a large amount of data, we recommend that you use the partition_data_proc procedure to commit data in smaller batches. This will effectively reduce problems caused by long-running transactions and data volume.

  • For subpartition sets, you must partition the data layer by layer, starting from the highest level. This means you must first run this function, then execute create_sub_parent() to create additional partition levels. Subsequently, you must run this function again on each newly created sub-parent table.

Syntax
partition_data_time(
    p_parent_table text
    , p_batch_count int DEFAULT 1
    , p_batch_interval interval DEFAULT NULL
    , p_lock_wait numeric DEFAULT 0
    , p_order text DEFAULT 'ASC'
    , p_analyze boolean DEFAULT true
    , p_source_table text DEFAULT NULL
    , p_ignored_columns text[] DEFAULT NULL
)
RETURNS bigint

partition_data_id(
    p_parent_table text
    , p_batch_count int DEFAULT 1
    , p_batch_interval bigint DEFAULT NULL
    , p_lock_wait numeric DEFAULT 0
    , p_order text DEFAULT 'ASC'
    , p_analyze boolean DEFAULT true
    , p_source_table text DEFAULT NULL
    , p_ignored_columns text[] DEFAULT NULL
)
RETURNS bigint
Parameters

Parameter

Type

Required

Default

Description

p_parent_table

text

Yes

None

The parent table of the partition set (must include the schema name).

p_batch_count

int

No

1

The number of batches to process in a single function call.

p_batch_interval

interval/bigint

No

NULL

The size of the data interval to migrate in each batch. If not specified, the partition table's own interval is used.

Important

If moving data from the default table, this value must not be smaller than the partition interval. If moving data from a default table source that is not part of the partition set, you can set this interval smaller than the partition interval to help avoid moving large amounts of data in a long-running transaction.

p_lock_wait

numeric

No

0

The number of seconds to wait for a row lock. 0 means wait indefinitely.

p_order

text

No

'ASC'

The order of data migration.

  • 'ASC': Ascending

  • 'DESC: Descending

p_analyze

boolean

No

true

Whether to run ANALYZE on the parent table after creating a new partition to update statistics. You can skip ANALYZE by setting this parameter to false to speed up moving large amounts of data. If set to false, we recommend manually running ANALYZE on the partition set after completion to ensure statistics are updated correctly.

p_source_table

text

No

NULL

Specifies a source table from which to move data into the partition set. If not specified, data is migrated from the default partition.

p_ignored_columns

text[]

No

NULL

An array of column names to ignore during data migration. This is mainly used for handling columns with the GENERATED ALWAYS attribute.

partition_data_proc()

This function is a stored procedure that calls the partition_data_* functions in a loop with independent transaction batches. We recommend that you use this procedure when you migrate large amounts of data to avoid long-running transactions and lock contention.

Syntax
partition_data_proc (
    p_parent_table text
    , p_loop_count int DEFAULT NULL
    , p_interval text DEFAULT NULL
    , p_lock_wait int DEFAULT 0
    , p_lock_wait_tries int DEFAULT 10
    , p_wait int DEFAULT 1
    , p_order text DEFAULT 'ASC'
    , p_source_table text DEFAULT NULL
    , p_ignored_columns text[] DEFAULT NULL
    , p_quiet boolean DEFAULT false
)
Parameters

Parameter

Type

Required

Default

Description

p_parent_table

text

Yes

None

The parent table of the partition set.

p_loop_count

int

No

NULL

The number of times to loop. If not set, all data in the source table will be processed.

p_interval

text

No

NULL

Passed as p_batch_interval to the underlying function, defining the amount of data processed in each transaction batch.

p_lock_wait

int

No

0

The number of seconds to wait for a row lock. 0 means wait indefinitely.

p_lock_wait_tries

int

No

10

The number of times to try to acquire a lock.

p_wait

int

No

1

The number of seconds to pause after each batch commit to reduce write load.

p_order

text

No

'ASC'

The order of data migration.

  • 'ASC': Ascending

  • 'DESC: Descending

p_source_table

text

No

NULL

The data source table.

p_ignored_columns

text[]

No

NULL

The columns to ignore during data migration.

p_quiet

boolean

No

false

Procedures cannot return values, so by default they emit a NOTICE to show progress. Set this option to disable these notices.

Maintain partitions

These functions are used for routine partition management, monitoring, and information queries.

run_maintenance()

The core maintenance function of pg_partman, which should be called periodically using cron or a Background Worker. It is responsible for automatically creating new partitions and enforcing data retention policies.

Syntax
run_maintenance(
    p_parent_table text DEFAULT NULL
    , p_analyze boolean DEFAULT false
)
RETURNS void
Parameters

Parameter

Type

Required

Default

Description

p_parent_table

text

No

NULL

The partition set to maintain.

  • If specified, only this partition set is maintained, regardless of the automatic_maintenance setting.

  • If not specified, all partition sets with automatic_maintenance set to 'on' are maintained.

p_analyze

boolean

No

false

Whether to run ANALYZE on the parent table after creating a new partition.

For large partition sets, ANALYZE can take a long time to execute. If run_maintenance() manages multiple partitions in a single run, this can lead to resource contention during the completion of ANALYZE. However, to ensure the full effectiveness of constraint exclusion or partition pruning, ANALYZE must eventually be run once from the parent level. Setting this parameter to true will execute ANALYZE on any partition set where at least one new partition was created. If no new partitions are created in a partition set, ANALYZE will not be executed, even if this parameter is set to true.


run_maintenance_proc()

The procedure version of run_maintenance(). It uses independent transactions for the maintenance of each partition set, which can reduce lock contention caused by long-running transactions when you manage many partition sets. The Background Worker does not use this procedure. It uses the standard run_maintenance() function.

Syntax
run_maintenance_proc(
    p_wait int DEFAULT 0
    , p_analyze boolean DEFAULT NULL
)
Parameters

Parameter

Type

Required

Default

Description

p_wait

int

No

0

The number of seconds to wait between maintaining each partition set.

p_analyze

boolean

No

NULL

Same as p_analyze in run_maintenance().

check_default()

Checks for the presence of data in all default partitions managed by pg_partman and returns the default tables that contain data, along with their row counts. This is an important means of monitoring whether partitioning is working correctly. You can use partition_data_time() and partition_data_id() to move data from these parent/default tables to the correct partitions.

Syntax
check_default(
    p_exact_count boolean DEFAULT true
)
Parameters

Parameter

Type

Required

Default

Description

p_exact_count

boolean

No

true

Whether to return an exact row count. Set to false to speed up the check, reporting only whether data exists.

show_partitions()

Lists all partitions for a given partition set.

Note

Tables are returned in the logical order of the partition interval, not in the native sort order of their names.

Syntax
show_partitions(
    p_parent_table text
    , p_order text DEFAULT 'ASC'
    , p_include_default boolean DEFAULT false
)
RETURNS TABLE (
    partition_schemaname text
    , partition_tablename text
)
Parameters

Parameter

Type

Required

Default

Description

p_parent_table

text

Yes

None

The parent table of the partition set.

p_order

text

No

'ASC'

The sort order of the results.

  • 'ASC': Ascending

  • 'DESC': Descending

p_include_default

boolean

No

false

Whether to include the default partition in the results.

show_partition_name()

Given a value, returns the name of the child partition to which it should belong, regardless of whether the partition actually exists.

Syntax
show_partition_name(
    p_parent_table text
    , p_value text
    , OUT partition_schema text
    , OUT partition_table text
    , OUT suffix_timestamp timestamptz
    , OUT suffix_id bigint
    , OUT table_exists boolean
)
RETURNS record
Parameters

Parameter

Type

Required

Default

Description

p_parent_table

text

Yes

None

The parent table of the partition set.

p_value

text

Yes

None

A time or numeric/ID value (passed as text) used to determine the partition it belongs to.

Note

If using epoch time partitioning, give the timestamp value, not the integer epoch value. You can use to_timestamp() to convert the epoch value.

OUT partition_schema

text

-

-

The partition schema name.

OUT partition_table

text

-

-

The partition name.

OUT suffix_timestamp or OUT suffix_id

timestamptz or bigint

-

-

The partition name suffix.

OUT table_exists

boolean

-

-

Whether the partition actually exists.

show_partition_info()

Given a partition name, returns information about its boundary values.

Syntax
show_partition_info(
    p_child_table text
    , p_partition_interval text DEFAULT NULL
    , p_parent_table text DEFAULT NULL
    , OUT child_start_time timestamptz
    , OUT child_end_time timestamptz
    , OUT child_start_id bigint
    , OUT child_end_id bigint
    , OUT suffix text
)
RETURNS record
Parameters

Parameter

Type

Required

Default

Description

p_child_table

text

Yes

None

The name of the partition (must include the schema name).

p_partition_interval

text

No

NULL

Specifies the partition interval to calculate the boundaries. If not provided, it is looked up from the part_config table.

p_parent_table

text

No

NULL

Provide the parent table name to optimize internal queries.

OUT child_start_time & child_end_time

timestamptz

-

-

If the partition set is time-based, the function returns values for these output parameters. Otherwise, it returns NULL.

Note

The start value (child_start_time) is inclusive, and the end value (child_end_time) is exclusive, which is exactly consistent with the partition boundaries defined in the database.

OUT child_start_id & child_end_id

bigint

-

-

If the partition set is integer-based, the function returns values for these output parameters. Otherwise, it returns NULL.

Note

The start value (child_start_id) is inclusive, and the end value (child_end_id) is exclusive, which is exactly consistent with the partition boundaries defined in the database.

OUT suffixtext

text

-

-

Outputs the text part appended to the partition name that identifies its content, excluding _p, for example, 20230324 or 920000. This is useful for generating custom suffixes similar to pg_partman.

apply_constraints()/drop_constraints()/reapply_constraints_proc()

Manages the extra CHECK constraints defined in the constraint_cols column of part_config.

  • apply_constraints(): Applies constraints to the partitions of a given partition set. All constraint names are prefixed with partmanconstr_.

    Note
    • You do not need to call this function manually to maintain custom constraints. Adding constraints to old partitions is managed automatically when new partitions are created.

    • If a pg_partman constraint already exists on a partition, the function skips the existing constraint to avoid duplicate creation.

    • If all given columns are NULL, no constraint is created.

    • If a partition parameter is provided, the constraint is applied only to that partition.

    • If no partition parameter is provided, the constraint is applied to the last partition that is older than the optimize_constraint value. For example, if optimize_constraint is 30, the constraint will be applied to the 31st partition before the current one, provided that partition pre-creation is up to date.

    • To apply constraints to all old partitions, use the reapply_constraints_proc procedure. This method has options to simplify constraint application with minimal performance impact.

    • p_job_id is for internal use, which allows logs to be merged into the original job that called this function.

    apply_constraints(
        p_parent_table text
        , p_child_table text DEFAULT NULL
        , p_analyze boolean DEFAULT FALSE
        , p_job_id bigint DEFAULT NULL
    )
    RETURNS void
  • drop_constraints(): Drops the constraints created by pg_partman for the columns configured in part_config. This makes it easy to clean up constraints when you need to edit old data and the constraints do not allow it.

    Note
    • Only drops constraints on the given partition and configured columns that start with partmanconstr_*.

    • To drop constraints on all partitions, use the reapply_constraints_proc procedure. This method has options to simplify constraint dropping with minimal performance impact.

    • The p_debug parameter will display the constraint drop statements used.

    drop_constraints(
        p_parent_table text
        , p_child_table text
        , p_debug boolean DEFAULT false
    )
    RETURNS void
  • reapply_constraints_proc(): Applies or drops constraints in bulk on all partitions, committing in batches to avoid lock contention.

    reapply_constraints_proc(
        p_parent_table text
        , p_drop_constraints boolean DEFAULT false
        , p_apply_constraints boolean DEFAULT false
        , p_wait int DEFAULT 0
        , p_dryrun boolean DEFAULT false
    )

Parameter

Type

Required

Default

Description

p_parent_table

text

Yes

None

The parent table of the created partition set.

p_drop_constraints

boolean

No

false

Drops all constraints managed by pg_partman. Drops constraints on all partitions, including current and future tables.

p_apply_constraints

boolean

No

false

Applies constraints on the configured columns to all partitions older than the optimize_constraint value.

p_wait

int

No

0

The number of seconds to wait after applying a constraint drop or add to a table before continuing to the next table.

p_dryrun

boolean

No

false

Runs this procedure without actually executing the drop/apply constraint commands. Only outputs which tables the commands would be run on as NOTICE messages.


Other maintenance functions

  • dump_partitioned_table_definition(): Generates a create_parent() statement to rebuild the partition set configuration and an UPDATE statement to set the additional parameters stored in part_config.

    Note
    • Currently, this function supports only single-level partition sets.

    • The SQL generated by p_ignore_template requires the template table to be created before running. If you have not made any modifications to the template table, it is safe to pass true here, and the generated SQL will tell pg_partman to generate a new template table. However, for safety, we recommend that you use pg_dump to export the template tables and restore them before you use the generated SQL to preserve any template override settings.

    dump_partitioned_table_definition(
      p_parent_table text,
      p_ignore_template_table boolean DEFAULT false
    )
    RETURNS text
    
  • partition_gap_fill(): Checks for and fills any gaps that may exist in the partition sequence. Starting from the current smallest partition, it fills any encountered gaps based on the partition interval, up to the current largest partition. It returns the number of partitions created. If no partitions are created, it returns 0.

    partition_gap_fill(
        p_parent_table text
    )
    RETURNS integer
  • reapply_privileges(): Reapplies the ownership and permissions of the parent table to all partitions.

    Note
    • Permissions owned by the parent table will be granted to all partitions. Permissions not owned by the parent table will be revoked (CASCADE).

    • The permissions checked are: SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, and TRIGGER.

    • For large partition sets, this can be a very time-consuming operation, so it is designed as a standalone function. The function applies only permissions that are different from the parent table, but it still requires system catalog lookups and comparisons for each child partition and all its individual permissions.

    reapply_privileges(
        p_parent_table text
    )
    RETURNS void
  • stop_sub_partition(): Stops automatic maintenance for a subpartition set while it preserves maintenance for its parent partition. By default, if you undo a partition that is also a partition itself, it will not prevent other partitions of that parent partition set from continuing to be subpartitioned unless you also undo its parent partition set. To address this situation, where you may not want to delete the parent table but do not want to continue creating subpartitions, you can use this function.

    Note

    This function removes only the parent table entry from the part_config_sub table.

    stop_sub_partition(
        p_parent_table text
    )
    RETURNS boolean

Destroy partitions

These functions are used to undo a partition structure or delete old partitions according to a retention policy.

undo_partition()

Moves data from all partitions of a partition set to a single target table and removes the partition structure. This is a data movement operation, so use it with caution.

Note
  • When this function is run, the undo_in_progress column in the configuration table is set to true. This will stop all partition creation and retention management.

  • By default, partitions are not dropped (DROP), but are detached (DETACH). This will make the original partitions empty, standalone tables.

  • If no batch parameters are set manually, each run of the function will move all data from one partition to the target table.

  • Once all partitions are detached or dropped, the configuration data is automatically removed from pg_partman.

  • For subpartitioned tables, you need to start the undo operation from the lowest-level parent table and then work your way up layer by layer.

Syntax
undo_partition(
    p_parent_table text
    , p_target_table text
    , p_loop_count int DEFAULT 1
    , p_batch_interval text DEFAULT NULL
    , p_keep_table boolean DEFAULT true
    , p_lock_wait numeric DEFAULT 0
    , p_ignored_columns text[] DEFAULT NULL
    , p_drop_cascade boolean DEFAULT false
    , OUT partitions_undone int
    , OUT rows_undone bigint)
RETURNS record
Parameters

Parameter

Type

Required

Default

Description

p_parent_table

text

Yes

None

The parent table of the partition set. Must include the schema name and match the parent table name already configured in pg_partman.

p_target_table

text

Yes

None

A table with a schema name that will receive the data from the old partition tables.

p_loop_count

int

No

1

The number of batches to process in a single call.

p_batch_interval

text

No

NULL

The size of the data interval to move in each batch. Can be set smaller than the partition interval to break up very large partitions into smaller commit batches. If not specified or if the provided interval is larger than the partition interval, the configured partition interval is used. Note that the value of this parameter must be passed as text.

p_keep_table

boolean

No

true

Whether to keep or drop the empty partition after data migration.

  • true: Keep

  • false: The resource is deleted.

Note

At least two batches are required to actually remove a table from the partition set.

p_lock_wait

numeric

No

0

The number of seconds to wait for a table or row to be unlocked before timing out. A value of 0 means wait indefinitely.

p_ignored_columns

text[]

No

NULL

This option allows filtering out specific columns when moving data from a partition to the target table. This is usually only needed when using columns of type GENERATED ALWAYS, as inserting values directly would cause the move to fail. The parameter is a text array of column names.

p_drop_cascade

boolean

No

false

Whether to cascade drop subpartitions. Only effective when p_keep_table is false.

Note

A cascade drop will cause all subpartition tables to be dropped when the parent table is dropped.

undo_partition_proc()

The procedure version of undo_partition(). We recommend that you use this procedure when you undo partitions that contain a large amount of data, to commit in batches and avoid long-running transactions.

Syntax
undo_partition_proc(
    p_parent_table text
    , p_target_table text DEFAULT NULL
    , p_loop_count int DEFAULT NULL
    , p_interval text DEFAULT NULL
    , p_keep_table boolean DEFAULT true
    , p_lock_wait int DEFAULT 0
    , p_lock_wait_tries int DEFAULT 10
    , p_wait int DEFAULT 1
    , p_ignored_columns text[] DEFAULT NULL
    , p_drop_cascade boolean DEFAULT false
    , p_quiet boolean DEFAULT false
)
Parameters

Its parameters are similar to undo_partition(), with some additional parameters to control batch processing behavior.

Parameter

Type

Required

Default

Description

p_interval

text

No

NULL

Passed as the p_batch_interval parameter to the undo_partition() function. Used to set an interval smaller than the partition interval to commit data in batches. If not set, the partition interval is used by default.

p_lock_wait_tries

int

No

10

Sets the number of times the procedure will attempt to wait for the time set by p_lock_wait.

p_wait

int

No

1

Causes the procedure to pause for the specified number of seconds between each commit (batch) to reduce write load.

p_quiet

boolean

No

false

Sub-procedures cannot return values, so by default they emit a NOTICE to show progress. Set this option to suppress these notices.

drop_partition_time()/drop_partition_id()

Manually triggers the deletion or detachment of old tables based on a retention policy. By default, old tables are only detached, not actually deleted. We recommend that you use the run_maintenance() function with a configured retention policy to automatically delete old tables, rather than calling this function directly.

Syntax
drop_partition_time(
    p_parent_table text
    , p_retention interval DEFAULT NULL
    , p_keep_table boolean DEFAULT NULL
    , p_keep_index boolean DEFAULT NULL
    , p_retention_schema text DEFAULT NULL
    , p_reference_timestamp timestamptz DEFAULT CURRENT_TIMESTAMP
)
RETURNS int

drop_partition_id(
    p_parent_table text
    , p_retention bigint DEFAULT NULL
    , p_keep_table boolean DEFAULT NULL
    , p_keep_index boolean DEFAULT NULL
    , p_retention_schema text DEFAULT NULL
)
RETURNS int
Parameters

Parameter

Type

Required

Default

Description

p_parent_table

text

Yes

None

The parent table of the partition set.

p_retention

interval/bigint

No

NULL

Manually specifies the retention policy. If not provided, the configuration from the part_config table is used.

p_keep_table

boolean

No

NULL

Whether to keep or drop the table when un-inheriting it.

  • true: Detach the table.

  • false: Drop the table.

p_keep_index

boolean

No

NULL

Whether to keep or drop indexes when un-inheriting a partition.

  • true: Keep

  • false: Drop

p_retention_schema

text

No

NULL

Moves expired tables to this schema for archiving instead of dropping them.

p_reference_timestamp

timestamptz

No

CURRENT_TIMESTAMP

(Time-based partitioning only) Specifies a different reference timestamp to determine which partitions should be affected.

Configuration tables

All behavior of pg_partman is driven by two core configuration tables. When you create a partition set using the create_parent() or create_sub_parent() functions, the corresponding configuration is automatically inserted into these tables. You can also directly modify the records in these tables to dynamically adjust the behavior of a partition set.

part_config

This table is the main configuration center for pg_partman and stores the partitioning policies and maintenance settings for all top-level parent tables.

Configuration item (column name)

Data type

Default value

Description

parent_table

text

None

The name of the parent table of the partition set.

control

text

None

The name of the control column used as the basis for partitioning. It must be a time or integer type column.

partition_interval

text

None

The partition interval. For time-based partitioning, it is an interval value (such as '1 day'). For numeric/ID partitioning, it is an integer range (such as '1000000').

partition_type

text

'range'

The partition type. Currently supports 'range' and 'list'.

premake

int

4

The number of partitions to pre-create. It means that, in addition to the current partition, this many future partitions are always maintained.

automatic_maintenance

text

'on'

Controls whether this partition set is automatically managed by the global run_maintenance() task. After setting it to 'off', you can still maintain it manually by specifying the parent table name.

template_table

text

None

The template table for new partitions. Newly created partitions will inherit indexes, constraints, and other attributes that cannot be inherited from the parent table from this template.

retention

text

NULL

The data retention policy. For time-based partitioning, it is an interval (such as '3 months'). For numeric/ID partitioning, it is an integer. Partitions older than this policy will be processed. NULL means permanent retention.

retention_schema

text

NULL

When an old partition expires, move it to this specified schema for archiving instead of deleting it. This option takes precedence over retention_keep_table.

retention_keep_table

boolean

true

Controls how expired partitions are handled.

  • true means only detach (DETACH) the table from the partition set.

  • false means completely drop (DROP) the table.

retention_keep_index

boolean

true

Controls whether to keep the indexes on the table when it is detached.

  • true: Keep its indexes when the partition is detached.

  • false: Drop its indexes when the partition is detached.

retention_keep_publication

boolean

false

Controls whether to keep the detached table in its original logical replication publication.

  • true: Keep it in the publication.

  • false: Remove it from the publication.

epoch

text

'none'

Used when the partition key column is an integer representing time (epoch).

  • 'seconds'

  • 'milliseconds'

  • 'microseconds'

  • 'nanoseconds'

constraint_cols

text[]

NULL

An array of column names. pg_partman automatically creates CHECK constraints on these columns for old partitions to optimize query performance through constraint exclusion.

optimize_constraint

int

30

Defines how old a partition must be before applying the constraints defined in constraint_cols. The value is the number of partitions relative to the latest partition. The default value of 30 means these constraints will be created on partitions that are 30 positions earlier than the latest partition containing data.

constraint_valid

boolean

true

Controls whether the constraints defined by constraint_cols are created as valid (VALID).

  • true: Valid (VALID).

  • false: Invalid (NOT VALID), which can speed up the maintenance process, but the constraints must be manually validated before they take effect.

infinite_time_partitions

boolean

false

Whether to continue creating new time partitions even when no new data is written.

  • true: Create new partitions even without new data.

  • false: If no new data is inserted, new partitions will not be created in a time-based partition set to avoid creating an infinite number of empty tables.

datetime_string

text

None

The date-time formatting string used to generate the suffix for partition names (for example, YYYY_MM_DD).

inherit_privileges

boolean

false

Whether to inherit the permissions and ownership of the parent table to all partitions. Enable this only if you need direct access to partitions.

  • true: Inherit.

  • false: Do not inherit.

ignore_default_data

boolean

true

Whether maintenance tasks ignore data in the default partition when deciding whether to create new partitions. Temporarily set this to false to fix issues. However, this may cause gaps in partition coverage, making the situation of data entering the default table worse. Therefore, do not enable this option long-term after fixing maintenance issues.

maintenance_order

int

NULL

Defines the execution order when run_maintenance() maintains multiple partition sets, executed in ascending numerical order.

  • A value of NULL means the partition set will run after those with defined values, and partition sets set to NULL will run in an undetermined order.

  • For subpartition sets, by default, partitions inherit their parent table's order. If the default value is kept, partitions will run in logical order when the parent table maintenance runs.

subscription_refresh

text

NULL

The name of the logical replication subscription to refresh when maintenance runs. If your partition set subscribes to a publication that adds/removes tables, and you need the partition set to be aware of these changes, you must use this option to specify the subscription name. Otherwise, unless refreshed by other means, the subscription will never be aware of new tables added by the publisher. For more information, see ALTER SUBSCRIPTION.

sub_partition_set_full

boolean

false

Marks whether the subpartition set has been fully created. When there are many subpartition sets, this allows run_maintenance() to run more efficiently.

undo_in_progress

boolean

false

When undo_partition() runs, this flag is set to true, pausing all maintenance operations.

maintenance_last_run

timestamptz

NULL

Records the timestamp of the last successful maintenance run for this partition set. This can be used as a monitoring metric to ensure partition maintenance is running normally.

part_config_sub

This table stores the configuration for subpartitions. Its structure is basically the same as part_config, but with one key difference: it uses the sub_parent column to identify its immediate parent table.

  • sub_parent (text): The name of the parent table of the subpartition set. This table itself is a partition of the top-level parent table.

  • Other columns: All other columns in the table, such as partition_interval, retention, and premake, have the same meaning as in part_config, but their scope is the current subpartition set.

You do not need to review the definitions of all columns. Essentially, when pg_partman maintains a subpartition set, it looks up the configuration row in the part_config_sub table using sub_parent as the key and applies the policy defined in that row.