The pg_pathman is a Postgres Pro extension that
provides an optimized partitioning solution for large and
distributed databases. Using pg_pathman, you can:
Partition large databases without downtime.
Speed up query execution for partitioned tables.
Manage existing partitions and add new partitions on the fly.
Add foreign tables as partitions.
Join partitioned tables for read and write operations.
The extension is compatible with Postgres Pro 9.5 or higher.
The pg_pathman extension is included into the
Postgres Pro. Once you have
Postgres Pro installed, complete
the following steps to enable pg_pathman:
Add pg_pathman to the
shared_preload_libraries variable in the
postgresql.conf file:
shared_preload_libraries = 'pg_pathman'
pg_pathman may have conflicts with other
extensions that use the same hook functions. For example,
pg_pathman may interfere with the
pg_stat_statements extension as they both
use ProcessUtility_hook. If you run into
this issue, try reordering libraries specified in this
parameter:
shared_preload_libraries = 'pg_pathman, pg_stat_statements'
Restart the Postgres Pro instance for the settings to take effect.
Create the pg_pathman extension using the
following query:
CREATE EXTENSION pg_pathman;
Once pg_pathman is enabled, you can start
partitioning tables.
You can also build pg_pathman from source code by executing the following command in the pg_pathman directory:
make install USE_PGXS=1
When this operation is complete, follow the steps described above to complete the setup.
In addition, do not forget to set the PG_CONFIG variable if you want to test pg_pathman on a custom build of Postgres Pro. For details, see
Building and Installing PostgreSQL Extension Modules.
You can toggle pg_pathman or its specific custom
nodes on and off using GUC variables. For details, see Section F.35.5.1.
If you want to permanently disable
pg_pathman for a previously partitioned
table, use the disable_pathman_for()
function:
SELECT disable_pathman_for('range_rel');
All sections and data will remain unchanged and will be handled by the standard Postgres Pro inheritance mechanism.
If you already have a previous version of pg_pathman installed, complete the following steps to upgrade to a newer version:
Install Postgres Pro.
Restart your Postgres Pro cluster.
Execute the following queries:
ALTER EXTENSION pg_pathman UPDATE TO version;
SET pg_pathman.enable = t;where version is the pg_pathman version number, such as 1.3.
As your database grows, indexing mechanisms may become inefficient and cause high latency as you run queries. To improve performance, ensure scalability, and optimize database administration processes you can use partitioning — splitting a large table into smaller pieces, with each row moved to a single partition according to the partitioning key. Postgres Pro supports partitioning via table inheritance. Each partition is created as a child table with a CHECK constraint. For example:
CREATE TABLE test (id SERIAL PRIMARY KEY, title TEXT); CREATE TABLE test_1 (CHECK ( id >= 100 AND id < 200 )) INHERITS (test); CREATE TABLE test_2 (CHECK ( id >= 200 AND id < 300 )) INHERITS (test);
However, too many partitions may cause significant planning
overhead as the query planner has to perform an exhaustive search
and check constraints on each partition to build a query plan. The
pg_pathman extension resolves this issue with
optimized planning algorithms and partition functions based on the
internal structure of the partitioned tables. For details on
pg_pathman implementation specifics, see
Section F.35.4.
The pg_pathman extension supports the
following partitioning strategies:
Hash — maps rows to partitions using a generic hash function. Choose this strategy if most of your queries will be of the exact-match type.
Range — maps rows to partitions based on partitioning key ranges
assigned to each partition. Choose this strategy if your
database contains numeric data that you are likely to query or
manage by ranges. For example, you may want to query historical
data by years, or review experiment results by specific numeric
ranges. To achieve performance gains,
pg_pathman uses the binary search algorithm.
By default, pg_pathman migrates all data from the parent table
to the newly created partitions at once (blocking
partitioning). This approach enables you to
restructure the table in a single transaction, but may cause
downtime if you have a lot of data. If it is critical to avoid
downtime, you can use concurrent
partitioning. In this case,
pg_pathman writes all the updates to
the newly created partitions, but keeps the original data in the
parent table until you explicitly migrate it. This enables you
to partition large databases without downtime, as you can choose
convenient time for migration and copy data in small batches
without blocking other transactions. For details on concurrent
partitioning, see Section F.35.2.2.
To perform hash partitioning with
pg_pathman, run the
create_hash_partitions() function:
create_hash_partitions(relation REGCLASS,
attribute TEXT,
partitions_count INTEGER,
partition_data BOOLEAN DEFAULT TRUE,
partition_names TEXT[] DEFAULT NULL,
tablespaces TEXT[] DEFAULT NULL)
The pg_pathman module creates the specified number of
partitions based on the hash function. Optionally,
you can specify partition names and tablespaces by setting
partition_names and
tablespaces options, respectively.
You cannot add or remove partitions after the parent table is split. If required, you can replace the specified partition with another table:
replace_hash_partition(old_partition REGCLASS,
new_partition REGCLASS,
lock_parent BOOL DEFAULT TRUE);
When set to true, lock_parent parameter will prevent any INSERT/UPDATE/ALTER TABLE queries to parent table.
If you omit the optional partition_data parameter
or set it to true, all the data from the
parent table gets migrated to partitions. The
pg_pathman module blocks the table for
other transactions until data migration completes. To avoid
downtime, you can set the partition_data
parameter to false and later use the
partition_table_concurrently() function to
migrate your data to partitions without blocking other
queries. For details, see the Section F.35.2.2.
The pg_pathman module provides the following functions for
range partitioning:
create_range_partitions() — creates
partitions based on the specified interval and the initial
partitioning key. New partitions are created automatically
when you insert data outside of the initial range.
create_partitions_from_range() — creates
partitions within the specified range. If required, you can
add new partitions manually using partition management functions. For details, see Section F.35.5.3.4.
If you are going to add new data outside of the existing
range, run the create_range_partitions()
function:
create_range_partitions(relation REGCLASS,
attribute TEXT,
start_value ANYELEMENT,
p_interval ANYELEMENT | INTERVAL,
p_count INTEGER DEFAULT NULL,
partition_data BOOLEAN DEFAULT TRUE)
The pg_pathman module creates partitions
based on the specified parameters. If you omit the optional
p_count parameter,
pg_pathman calculates the required number
of partitions based on the specified start value and interval.
If you insert new data outside of the existing partition
range, pg_pathman creates new partitions
automatically, keeping the specified interval. This approach
ensures that all partitions are of the same size, which can
improve query performance and facilitate database management.
If your current data range is unlikely to change, run the
create_partitions_from_range() function:
create_partitions_from_range(relation REGCLASS,
attribute TEXT,
start_value ANYELEMENT,
end_value ANYELEMENT,
p_interval ANYELEMENT | INTERVAL,
partition_data BOOLEAN DEFAULT TRUE)
In this case, pg_pathman does not create new partitions automatically, but you can use partition management functions to add partitions manually, if required.
By default, all the data from the parent table gets migrated
to the specified number of partitions. The pg_pathman module
blocks the table for other transactions until data migration
completes. To avoid
downtime, you can set the partition_data
parameter to false and later use the
partition_table_concurrently() function to
migrate your data to partitions without blocking other
queries. For details, see the Section F.35.2.2.
If it is critical to avoid downtime, you can perform concurrent
partitioning by setting the partition_data
parameter of the partitioning function to
false. In this case,
pg_pathman creates empty partitions, keeping
all the original data in the parent table. At the same time, all
the database updates are written to the newly created
partitions. You can later migrate the original data to
partitions without blocking other queries using the
partition_table_concurrently() function:
partition_table_concurrently(relation REGCLASS,
batch_size INTEGER DEFAULT 1000,
sleep_time FLOAT8 DEFAULT 1.0)
where:
relation is the parent table.
batch_size is the number of rows to copy from
the parent table to partitions at a time. You can set this
parameter to any integer value from 1 to 10000.
sleep_time is the time interval between
migration attempts, in seconds.
The pg_pathman module starts a background worker to move the data from the
parent table to partitions in small batches of the specified
batch_size. If one or more rows in the batch
are locked by other queries, pg_pathman waits
for the specified sleep_time and tries again,
up to 60 times. You can monitor the migration process in the
pathman_concurrent_part_tasks view that shows
the number of rows migrated so far:
[user]postgres: select * from pathman_concurrent_part_tasks ; userid | pid | dbid | relid | processed | status --------+-------+-------+-------+-----------+--------- user | 20012 | 12413 | test | 334000 | working (1 row)
If you need to stop data migration, run the
stop_concurrent_part_task() function at any
time:
SELECT stop_concurrent_part_task(relation REGCLASS);
pg_pathman completes the migration of the
current batch and terminates the migration process.
When pg_pathman migrates all the data
from the parent table, you can exclude the parent table from the
query plan. See the set_enable_parent()
function description for details.
pg_pathman provides multiple functions for
easy partition management. For details, see Section F.35.5.3.4.
You can add
partition
column containing the names of the underlying partitions
using the system attribute called
tableoid:
SELECT tableoid::regclass AS partition, * FROM partitioned_table;
Though indices on a parent table are not particularly useful
(since the parent table is supposed to be empty), they act as prototypes
for indices on partitions. For each index on the parent
table, pg_pathman creates a similar
index on each partition.
All running concurrent partitioning tasks can be listed
using the pathman_concurrent_part_tasks
view:
SELECT * FROM pathman_concurrent_part_tasks; userid | pid | dbid | relid | processed | status --------+------+-------+-------+-----------+--------- user | 7367 | 16384 | test | 472000 | working (1 row)
The pathman_partition_list in conjunction
with drop_range_partition() can be used
to drop range partitions in a more flexible way compared to
DROP TABLE:
SELECT drop_range_partition(partition, false) /* move data to parent */ FROM pathman_partition_list WHERE parent = 'part_test'::regclass AND range_min::int < 500; NOTICE: 1 rows copied from part_test_11 NOTICE: 100 rows copied from part_test_1 NOTICE: 100 rows copied from part_test_2 drop_range_partition ---------------------- dummy_test_11 dummy_test_1 dummy_test_2 (3 rows)
Consider an example of hash partitioning. First create a table with an integer column:
CREATE TABLE items ( id SERIAL PRIMARY KEY, name TEXT, code BIGINT); INSERT INTO items (id, name, code) SELECT g, md5(g::text), random() * 100000 FROM generate_series(1, 100000) as g;
Now run the create_hash_partitions() function
with appropriate arguments:
SELECT create_hash_partitions('items', 'id', 100);
This will create new partitions and move the data from the parent table to partitions.
Here is an example of the query performing filtering by partitioning key:
SELECT * FROM items WHERE id = 1234; id | name | code ------+----------------------------------+------ 1234 | 81dc9bdb52d04dc20036dbd8313ed055 | 1855 (1 row) EXPLAIN SELECT * FROM items WHERE id = 1234; QUERY PLAN ------------------------------------------------------------------------------------ Append (cost=0.28..8.29 rows=0 width=0) -> Index Scan using items_34_pkey on items_34 (cost=0.28..8.29 rows=0 width=0) Index Cond: (id = 1234)
Notice that the Append node contains only one
child scan, which corresponds to the WHERE clause.
Pay attention to
the fact that pg_pathman excludes the
parent table from the query plan.
To access the parent table, use the ONLY modifier:
EXPLAIN SELECT * FROM ONLY items; QUERY PLAN ------------------------------------------------------ Seq Scan on items (cost=0.00..0.00 rows=1 width=45)
Consider an example of range partitioning. Let's create a table containing some dummy logs:
CREATE TABLE journal (
id SERIAL,
dt TIMESTAMP NOT NULL,
level INTEGER,
msg TEXT);
-- similar index will also be created for each partition
CREATE INDEX ON journal(dt);
-- generate some data
INSERT INTO journal (dt, level, msg)
SELECT g, random() * 6, md5(g::text)
FROM generate_series('2015-01-01'::date, '2015-12-31'::date, '1 minute') as g;
Run the create_range_partitions() function to
create partitions so that each partition would contain the data
for one day:
SELECT create_range_partitions('journal', 'dt', '2015-01-01'::date, '1 day'::interval);
It will create 364 partitions and move the data from the parent table to partitions.
New partitions are appended automatically by insert trigger, but it can be done manually with the following functions:
-- add new partition with specified range
SELECT add_range_partition('journal', '2016-01-01'::date, '2016-01-07'::date);
-- append new partition with default range
SELECT append_range_partition('journal');
The first one creates a partition with specified range. The second one creates a partition with default interval and appends it to the partition list. It is also possible to attach an existing table as partition. For example, we may want to attach an archive table (or even foreign table from another server) for some outdated data:
CREATE FOREIGN TABLE journal_archive (
id INTEGER NOT NULL,
dt TIMESTAMP NOT NULL,
level INTEGER,
msg TEXT)
SERVER archive_server;
SELECT attach_range_partition('journal', 'journal_archive', '2014-01-01'::date, '2015-01-01'::date);
The attached table must have the same columns as the partitioned table, except for the dropped columns. The attached columns must have the same type, collation, and not NULL settings as the original columns.
To merge to adjacent partitions, use the
merge_range_partitions() function:
SELECT merge_range_partitions('journal_archive', 'journal_1');
To split partition by value, use the
split_range_partition() function:
SELECT split_range_partition('journal_366', '2016-01-03'::date);
To detach partition, use the
detach_range_partition() function:
SELECT detach_range_partition('journal_archive');
Here is an example of the query performing filtering by partitioning key:
SELECT * FROM journal WHERE dt >= '2015-06-01' AND dt < '2015-06-03'; id | dt | level | msg --------+---------------------+-------+---------------------------------- 217441 | 2015-06-01 00:00:00 | 2 | 15053892d993ce19f580a128f87e3dbf 217442 | 2015-06-01 00:01:00 | 1 | 3a7c46f18a952d62ce5418ac2056010c 217443 | 2015-06-01 00:02:00 | 0 | 92c8de8f82faf0b139a3d99f2792311d ... (2880 rows) EXPLAIN SELECT * FROM journal WHERE dt >= '2015-06-01' AND dt < '2015-06-03'; QUERY PLAN ------------------------------------------------------------------ Append (cost=0.00..58.80 rows=0 width=0) -> Seq Scan on journal_152 (cost=0.00..29.40 rows=0 width=0) -> Seq Scan on journal_153 (cost=0.00..29.40 rows=0 width=0) (3 rows)
pg_pathman stores partitioning configuration in
the pathman_config table; each row contains a
single entry for a partitioned table (relation name, partitioning
column and its type). During the initialization stage the
pg_pathman module caches some information about
child partitions in the shared memory, which is used later for
plan construction. Before a SELECT query is executed,
pg_pathman traverses the condition tree in
search of expressions like:
VARIABLE OP CONST
where VARIABLE is a partitioning key,
OP is a comparison operator (supported
operators are =, <, <=, >, >=),
CONST is a scalar value. For example:
WHERE id = 150
Based on the partitioning type and condition's operator,
pg_pathman searches for the corresponding
partitions and builds the plan.
pg_pathman provides a couple of
custom
plan nodes which aim to reduce execution time, namely:
RuntimeAppend (overrides
Append plan node)
RuntimeMergeAppend (overrides
MergeAppend plan node)
PartitionFilter (drop-in replacement for
INSERT triggers)
PartitionFilter acts as a proxy
node for INSERT's child scan, which means it can
redirect output tuples to the corresponding partition:
EXPLAIN (COSTS OFF)
INSERT INTO partitioned_table
SELECT generate_series(1, 10), random();
QUERY PLAN
-----------------------------------------
Insert on partitioned_table
-> Custom Scan (PartitionFilter)
-> Subquery Scan on "*SELECT*"
-> Result
(4 rows)
RuntimeAppend and
RuntimeMergeAppend have much in common: they
come in handy in a case when WHERE condition takes form of:
VARIABLE OP PARAM
This kind of expressions can no longer be optimized at planning
time since the parameter's value is not known until the execution
stage takes place. The problem can be solved by embedding the
WHERE condition analysis routine into the
original Append's code, thus making it pick
only required scans out of a whole bunch of planned partition
scans. This effectively boils down to creation of a custom node
capable of performing such a check.
There are at least several cases that demonstrate usefulness of these nodes:
/* create table we're going to partition */
CREATE TABLE partitioned_table(id INT NOT NULL, payload REAL);
/* insert some data */
INSERT INTO partitioned_table
SELECT generate_series(1, 1000), random();
/* perform partitioning */
SELECT create_hash_partitions('partitioned_table', 'id', 100);
/* create ordinary table */
CREATE TABLE some_table AS SELECT generate_series(1, 100) AS VAL;
id = (select ... limit 1)
EXPLAIN (COSTS OFF, ANALYZE) SELECT * FROM partitioned_table
WHERE id = (SELECT * FROM some_table LIMIT 1);
QUERY PLAN
----------------------------------------------------------------------------------------------------
Custom Scan (RuntimeAppend) (actual time=0.030..0.033 rows=1 loops=1)
InitPlan 1 (returns $0)
-> Limit (actual time=0.011..0.011 rows=1 loops=1)
-> Seq Scan on some_table (actual time=0.010..0.010 rows=1 loops=1)
-> Seq Scan on partitioned_table_70 partitioned_table (actual time=0.004..0.006 rows=1 loops=1)
Filter: (id = $0)
Rows Removed by Filter: 9
Planning time: 1.131 ms
Execution time: 0.075 ms
(9 rows)
/* disable RuntimeAppend node */
SET pg_pathman.enable_runtimeappend = f;
EXPLAIN (COSTS OFF, ANALYZE) SELECT * FROM partitioned_table
WHERE id = (SELECT * FROM some_table LIMIT 1);
QUERY PLAN
----------------------------------------------------------------------------------
Append (actual time=0.196..0.274 rows=1 loops=1)
InitPlan 1 (returns $0)
-> Limit (actual time=0.005..0.005 rows=1 loops=1)
-> Seq Scan on some_table (actual time=0.003..0.003 rows=1 loops=1)
-> Seq Scan on partitioned_table_0 (actual time=0.014..0.014 rows=0 loops=1)
Filter: (id = $0)
Rows Removed by Filter: 6
-> Seq Scan on partitioned_table_1 (actual time=0.003..0.003 rows=0 loops=1)
Filter: (id = $0)
Rows Removed by Filter: 5
... /* more plans follow */
Planning time: 1.140 ms
Execution time: 0.855 ms
(306 rows)
id = ANY (select ...)
EXPLAIN (COSTS OFF, ANALYZE) SELECT * FROM partitioned_table
WHERE id = any (SELECT * FROM some_table limit 4);
QUERY PLAN
-----------------------------------------------------------------------------------------------------------
Nested Loop (actual time=0.025..0.060 rows=4 loops=1)
-> Limit (actual time=0.009..0.011 rows=4 loops=1)
-> Seq Scan on some_table (actual time=0.008..0.010 rows=4 loops=1)
-> Custom Scan (RuntimeAppend) (actual time=0.002..0.004 rows=1 loops=4)
-> Seq Scan on partitioned_table_70 partitioned_table (actual time=0.001..0.001 rows=10 loops=1)
-> Seq Scan on partitioned_table_26 partitioned_table (actual time=0.002..0.003 rows=9 loops=1)
-> Seq Scan on partitioned_table_27 partitioned_table (actual time=0.001..0.002 rows=20 loops=1)
-> Seq Scan on partitioned_table_63 partitioned_table (actual time=0.001..0.002 rows=9 loops=1)
Planning time: 0.771 ms
Execution time: 0.101 ms
(10 rows)
/* disable RuntimeAppend node */
SET pg_pathman.enable_runtimeappend = f;
EXPLAIN (COSTS OFF, ANALYZE) SELECT * FROM partitioned_table
WHERE id = any (SELECT * FROM some_table limit 4);
QUERY PLAN
-----------------------------------------------------------------------------------------
Nested Loop Semi Join (actual time=0.531..1.526 rows=4 loops=1)
Join Filter: (partitioned_table.id = some_table.val)
Rows Removed by Join Filter: 3990
-> Append (actual time=0.190..0.470 rows=1000 loops=1)
-> Seq Scan on partitioned_table (actual time=0.187..0.187 rows=0 loops=1)
-> Seq Scan on partitioned_table_0 (actual time=0.002..0.004 rows=6 loops=1)
-> Seq Scan on partitioned_table_1 (actual time=0.001..0.001 rows=5 loops=1)
-> Seq Scan on partitioned_table_2 (actual time=0.002..0.004 rows=14 loops=1)
... /* 96 scans follow */
-> Materialize (actual time=0.000..0.000 rows=4 loops=1000)
-> Limit (actual time=0.005..0.006 rows=4 loops=1)
-> Seq Scan on some_table (actual time=0.003..0.004 rows=4 loops=1)
Planning time: 2.169 ms
Execution time: 2.059 ms
(110 rows)
NestLoop involving
a partitioned table, which is omitted since it's
occasionally shown above.
To learn more about custom nodes, see Alexander Korotkov's blog.
There are several user-accessible GUC
variables designed to toggle pg_pathman or its specific custom
nodes on and off.
pg_pathman.enable — enable/disable the
pg_pathman module.
Default: on
pg_pathman.enable_runtimeappend —
toggle the RuntimeAppend custom node on/off.
Default: on
pg_pathman.enable_runtimemergeappend —
toggle the RuntimeMergeAppend custom node on/off.
Default: on
pg_pathman.enable_partitionfilter —
toggle the PartitionFilter custom node on/off.
Default: on
pg_pathman.enable_auto_partition —
toggle automatic partition creation on/off (per session).
Default: on
pg_pathman.insert_into_fdw — allow
INSERT operations into various foreign-data wrappers.
Possible values: disabled, postgres, and any_fdw.
Default: postgres
pg_pathman.override_copy — toggle COPY
statement hooking on/off.
Default: on
pathman_configThis table stores the list of partitioned tables. This is the main configuration storage.
CREATE TABLE IF NOT EXISTS pathman_config (
partrel REGCLASS NOT NULL PRIMARY KEY,
attname TEXT NOT NULL,
parttype INTEGER NOT NULL,
range_interval TEXT);
pathman_config_params
This table stores optional parameters that override standard pg_pathman
behavior.
CREATE TABLE IF NOT EXISTS pathman_config_params (
partrel REGCLASS NOT NULL PRIMARY KEY,
enable_parent BOOLEAN NOT NULL DEFAULT TRUE,
auto BOOLEAN NOT NULL DEFAULT TRUE,
init_callback REGPROCEDURE NOT NULL DEFAULT 0,
spawn_using_bgw BOOLEAN NOT NULL DEFAULT FALSE);
pathman_concurrent_part_tasksThis view lists all currently running concurrent partitioning tasks.
-- helper SRF function
CREATE OR REPLACE FUNCTION show_concurrent_part_tasks()
RETURNS TABLE (
userid REGROLE,
pid INT,
dbid OID,
relid REGCLASS,
processed INT,
status TEXT)
AS 'pg_pathman', 'show_concurrent_part_tasks_internal'
LANGUAGE C STRICT;
CREATE OR REPLACE VIEW pathman_concurrent_part_tasks
AS SELECT * FROM show_concurrent_part_tasks();
pathman_partition_listThis view lists all existing partitions, as well as their parents and range boundaries (NULL for hash partitions).
-- helper SRF function
CREATE OR REPLACE FUNCTION show_partition_list()
RETURNS TABLE (
parent REGCLASS,
partition REGCLASS,
parttype INT4,
partattr TEXT,
range_min TEXT,
range_max TEXT)
AS 'pg_pathman', 'show_partition_list_internal'
LANGUAGE C STRICT;
CREATE OR REPLACE VIEW pathman_partition_list
AS SELECT * FROM show_partition_list();
create_hash_partitions(relation REGCLASS,
attribute TEXT,
partitions_count INTEGER,
partition_data BOOLEAN DEFAULT TRUE,
partition_names TEXT[] DEFAULT NULL,
tablespaces TEXT[] DEFAULT NULL)
Performs hash partitioning for relation by
integer key attribute. The
partitions_count parameter specifies the
number of partitions to create; it cannot be changed afterwards.
If partition_data is true,
all the data will be automatically migrated from the parent
table to partitions. Note that data migration may take a while
to finish and the table will be locked until transaction
commits. See partition_table_concurrently()
for a lock-free way to migrate data. Partition creation callback
is invoked for each partition if set beforehand
(see set_init_callback()).
create_range_partitions(relation REGCLASS,
attribute TEXT,
start_value ANYELEMENT,
p_interval ANYELEMENT,
p_count INTEGER DEFAULT NULL,
partition_data BOOLEAN DEFAULT TRUE)
create_range_partitions(relation REGCLASS,
attribute TEXT,
start_value ANYELEMENT,
p_interval INTERVAL,
p_count INTEGER DEFAULT NULL,
partition_data BOOLEAN DEFAULT TRUE)
Performs range partitioning for relation by
partitioning key attribute. The
start_value argument specifies the initial value,
p_interval sets the default range for automatically created partitions or partitions created with
append_range_partition() or
prepend_range_partition()
If p_interval is set to NULL, automatic partition creation
is disabled. p_count is the
number of premade partitions. If p_count is not set, than
pg_pathman tries to determine the number of partitions based
on the attribute value. Partition creation callback is invoked
for each partition if set beforehand.
create_partitions_from_range(relation REGCLASS,
attribute TEXT,
start_value ANYELEMENT,
end_value ANYELEMENT,
p_interval ANYELEMENT,
partition_data BOOLEAN DEFAULT TRUE)
create_partitions_from_range(relation REGCLASS,
attribute TEXT,
start_value ANYELEMENT,
end_value ANYELEMENT,
p_interval INTERVAL,
partition_data BOOLEAN DEFAULT TRUE)
Performs range partitioning from specified range for
relation by partitioning key
attribute. Partition creation callback is
invoked for each partition if set beforehand.
partition_table_concurrently(relation REGCLASS)
Starts a background worker to move data from parent table to partitions. The worker utilizes short transactions to copy small batches of data (up to 10K rows per transaction) and thus doesn't significantly interfere with user's activity.
stop_concurrent_part_task(relation REGCLASS)
Stops a background worker performing a concurrent partitioning task. Note: worker will exit after it finishes relocating a current batch.
create_hash_update_trigger(parent REGCLASS)
Creates the trigger on UPDATE for hash partitions. The UPDATE
trigger isn't created by default because of the overhead. It's
useful in cases when the key attribute might change.
create_range_update_trigger(parent REGCLASS)
Same as above, but for a range-partitioned table.
replace_hash_partition(old_partition REGCLASS,
new_partition REGCLASS,
lock_parent BOOL DEFAULT TRUE)
Replaces the specified partition of hash-partitioned table with another table.
When set to true, the lock_parent parameter prevents any INSERT/UPDATE/ALTER TABLE queries to the parent table.
split_range_partition(partition REGCLASS,
value ANYELEMENT,
partition_name TEXT DEFAULT NULL)
Split range partition in two by
value, with the specified value included into the second partition.
Partition creation callback is invoked
for a new partition if available.
merge_range_partitions(partition1 REGCLASS, partition2 REGCLASS)
Merge two adjacent range partitions. First, data from
partition2 is copied to
partition1, then
partition2 is removed.
merge_range_partitions(partitions REGCLASS[])
Merge several adjacent range partitions (partitions must be specified in ascending or descending order). All the data will be accumulated in the first partition.
append_range_partition(p_relation REGCLASS,
partition_name TEXT DEFAULT NULL,
tablespace TEXT DEFAULT NULL)
Append new range partition with
pathman_config.range_interval as interval.
prepend_range_partition(p_relation REGCLASS,
partition_name TEXT DEFAULT NULL,
tablespace TEXT DEFAULT NULL)
Prepend new range partition with
pathman_config.range_interval as interval.
add_range_partition(relation REGCLASS,
start_value ANYELEMENT,
end_value ANYELEMENT,
partition_name TEXT DEFAULT NULL,
tablespace TEXT DEFAULT NULL)
Create new range partition for relation with
specified range bounds. If start_value
or end_value are NULL, than the corresponding
range bound will be infinite.
drop_range_partition(partition TEXT, delete_data BOOLEAN DEFAULT TRUE)
Drop range partition and all of its data if
delete_data is true.
attach_range_partition(relation REGCLASS,
partition REGCLASS,
start_value ANYELEMENT,
end_value ANYELEMENT)
Attach partition to the existing range-partitioned relation. The
attached table must have exactly the same structure as the
parent table, including the dropped columns. Partition creation
callback is invoked if set (see
pathman_config_params).
detach_range_partition(partition REGCLASS)
Detach partition from the existing range-partitioned relation.
disable_pathman_for(relation TEXT)
Permanently disable pg_pathman partitioning
mechanism for the specified parent table and remove the insert
trigger if it exists. All partitions and data remain unchanged.
drop_partitions(parent REGCLASS,
delete_data BOOLEAN DEFAULT FALSE)
Drop partitions of the parent table (both
foreign and local relations). If delete_data
is false, the data is copied to the parent
table first. Default is false.
set_interval(relation REGCLASS, value ANYELEMENT)
Update range-partitioned table interval. Note that interval must not
be negative and it must not be trivial, i.e. its value should be
greater than zero for numeric types, at least 1 microsecond for
timestamp and at least 1 day
for date.
set_enable_parent(relation REGCLASS, value BOOLEAN)
Include/exclude parent table into/from query plan. In original
Postgres Pro planner parent table is always included into query
plan even if it's empty which can lead to additional overhead.
You can use disable_parent() if you are never
going to use parent table as a storage. Default value depends on
the partition_data parameter that was
specified during initial partitioning in
create_range_partitions() or
create_partitions_from_range() functions. If
the partition_data parameter was
true then all data have already been migrated
to partitions and parent table disabled. Otherwise it is
enabled.
set_auto(relation REGCLASS, value BOOLEAN)
Enable/disable auto partition propagation (only for range partitioning). It is enabled by default.
set_init_callback(relation REGCLASS, callback REGPROC DEFAULT 0)
Set partition creation callback to be invoked for each attached
or created partition (both hash and range). The callback must
have the following signature:
part_init_callback(args JSONB) RETURNS VOID.
Parameter arg consists of several fields
whose presence depends on partitioning type:
/* Range-partitioned table abc (child abc_4) */
{
"parent": "abc",
"parttype": "2",
"partition": "abc_4",
"range_max": "401",
"range_min": "301"
}
/* Hash-partitioned table abc (child abc_0) */
{
"parent": "abc",
"parttype": "1",
"partition": "abc_0"
}
set_spawn_using_bgw(relation REGCLASS, value BOOLEAN)
When inserting new data beyond the partitioning range, use SpawnPartitionsWorker to create new partitions in a separate transaction.
Ildar Musin <i.musin@postgrespro.ru> Postgres Professional Ltd., Russia
Alexander Korotkov <a.korotkov@postgrespro.ru> Postgres Professional Ltd., Russia
Dmitry Ivanov <d.ivanov@postgrespro.ru> Postgres Professional Ltd., Russia