このトピックでは、pg_pathman プラグインの一般的な使用シナリオについて説明します。

このタスクについて

パーティション分割テーブルのパフォーマンスを向上させるため、POLARDB for PostgreSQL に pg_pathman プラグインが導入されました。 このプラグインは、パーティションの管理および最適化に使用できます。

pg_pathman 拡張を作成する

test=# create extension pg_pathman;
CREATE EXTENSION

インストール済みの拡張を表示する

以下のコマンドを実行して、インストール済みの拡張と pg_pathman プラグインのバージョンを表示します。

test=# \dx
                     List of installed extensions
    Name    | Version |   Schema   |           Description
------------+---------+------------+----------------------------------
 pg_pathman | 1.5     | public     | Partitioning tool for PostgreSQL
 plpgsql    | 1.0     | pg_catalog | PL/pgSQL procedural language
(2 rows)

プラグインをアップグレードする

POLARDB for PostgreSQL は、プラグインを定期的にアップグレードして、データベースサービスを良好な状態に保ちます。 プラグインをアップグレードするには、以下の手順を実行します。

  • 対応するクラスターを最新バージョンにアップグレードします。 なお、この機能は開発段階にあるため、アップグレードを実行するにはチケットを起票する必要があります。
  • 以下のステートメントを実行して、更新を完了します。
    ALTER EXTENSION pg_pathman UPDATE;
    SET pg_pathman.enable = t;

機能

  • ハッシュおよび範囲分割をサポートします。
  • 自動および手動パーティション管理をサポートします。 自動パーティション管理では、システムは関数を使用してパーティションを作成し、プライマリテーブルのデータをパーティションに移行します。 手動パーティション管理では、関数を使用して既存のテーブルをパーティションテーブルにアタッチしたり、テーブルをパーティション分割テーブルからデタッチしたりできます。
  • カスタムドメインや、整数、浮動小数点、日付などの一般的なデータ型を含む、複数の分割フィールドをサポートします。
  • 結合とサブクエリを使用して、分割テーブルの効果的なクエリ計画を作成できます。
  • RuntimeAppend および RuntimeMergeAppend カスタムプランノードで、実行時にパーティションを選択します。
  • PartitionFilter:効率の高い、INSERT トリガー互換の機能です。
  • 新しく挿入されたデータに対して自動的にパーティションを作成します (範囲パーティションのみ)。
  • COPY FROM/TO ステートメントをサポートし、パーティションでの直接の読み書きが可能です。
  • 分割フィールドを更新できます。 分割フィールドを更新するには、トリガーを追加する必要があります。 分割フィールドを更新する必要がない場合は、パフォーマンスへの悪影響を避けるためにトリガーを追加しないことを推奨します。
  • ユーザー定義のコールバック関数は、パーティションが作成されると自動的にトリガーされます。
  • ブロッキングなしで同時にテーブルを分割し、バックグラウンドでプライマリテーブルからパーティションへ自動的にデータを移行します。
  • postgres_fdw またはpg_pathman.insert_into_fdw=(disabled | postgres | any_fdw)パラメーターの設定により外部データラッパー (FDW) をサポートします。

使用方法

詳細については、「 https://github.com/postgrespro/pg_pathman」をご参照ください。

ビューおよびテーブル

pg_pathman プラグインは、関数を使用して分割テーブルを維持し、分割テーブルのステータスを表示するためのビューを作成します。以下に例を示します。

  1. pathman_config
    CREATE TABLE IF NOT EXISTS pathman_config (
        partrel         REGCLASS NOT NULL PRIMARY KEY,  -- The OID of the primary table.
        attname         TEXT NOT NULL,  -- The column name of the partition.
        parttype        INTEGER NOT NULL,  -- The type of the partition (hash or range).
        range_interval  TEXT,  -- The interval of range partitions.
    
        CHECK (parttype IN (1, 2)) /* check for allowed part types */ );
  2. pathman_config_params
    CREATE TABLE IF NOT EXISTS pathman_config_params (
        partrel        REGCLASS NOT NULL PRIMARY KEY,  -- The OID of the primary table.
        enable_parent  BOOLEAN NOT NULL DEFAULT TRUE,  -- Specifies whether to filter the primary table in the optimizer.
        auto           BOOLEAN NOT NULL DEFAULT TRUE,  -- Specifies whether to automatically expand partitions that do not exist during INSERT operations.
        init_callback  REGPROCEDURE NOT NULL DEFAULT 0);  -- The OID of the callback function when the partition is created.
  3. pathman_concurrent_part_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();
  4. pathman_partition_list
    -- 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();

パーティション管理

  1. 範囲パーティション
    範囲パーティションの作成には、4 つの管理関数を使用します。 開始値、間隔、およびパーティション数の指定には、2 つの関数を使用します。 これら 2 つの関数は以下のように定義されます。
    create_range_partitions(relation       REGCLASS,  -- The OID of the primary table.
                            attribute      TEXT,      -- The column name of the partition.
                            start_value    ANYELEMENT,  -- The start value.
                            p_interval     ANYELEMENT,  -- The interval, applicable to any type of partitioned tables.
                            p_count        INTEGER DEFAULT NULL,   --  The number of partitions.
                            partition_data BOOLEAN DEFAULT TRUE)   --  Specifies whether to immediately migrate data from the primary table to partitions. We recommend that you call the partition_table_concurrently() function to run non-blocking data migration.
    
    create_range_partitions(relation       REGCLASS,  -- The OID of the primary table.
                            attribute      TEXT,      -- The column name of the partition.
                            start_value    ANYELEMENT,  -- The start value.
                            p_interval     INTERVAL,    -- The interval of the interval type, applicable to ingestion-time partitioned tables.
                            p_count        INTEGER DEFAULT NULL,   --  The number of partitions.
                            partition_data BOOLEAN DEFAULT TRUE)   --  Specifies whether to immediately migrate data from the primary table to partitions. We recommend that you call the partition_table_concurrently() function to run non-blocking data migration.
    他の 2 つの関数は、開始値、終了値、および間隔の指定に使用します。 定義は以下のとおりです。
    create_partitions_from_range(relation       REGCLASS,  -- The OID of the primary table.
                                 attribute      TEXT,      -- The column name of the partition.
                                 start_value    ANYELEMENT,  -- The start value.
                                 end_value      ANYELEMENT,  -- The end value.
                                 p_interval     ANYELEMENT,  -- The interval, applicable to any type of partitioned tables.
                                 partition_data BOOLEAN DEFAULT TRUE)   --  Specifies whether to immediately migrate data from the primary table to partitions. We recommend that you call the partition_table_concurrently() function to run non-blocking data migration.
    
    create_partitions_from_range(relation       REGCLASS,  -- The OID of the primary table.
                                 attribute      TEXT,      -- The column name of the partition.
                                 start_value    ANYELEMENT,  -- The start value.
                                 end_value      ANYELEMENT,  -- The end value.
                                 p_interval     INTERVAL,    -- The interval of the interval type, applicable to ingestion-time partitioned tables.
                                 partition_data BOOLEAN DEFAULT TRUE)   --  Specifies whether to immediately migrate data from the primary table to partitions. We recommend that you call the partition_table_concurrently() function to run non-blocking data migration.
    例:
    Create a primary table that needs to be partitioned.
    postgres=# create table part_test(id int, info text, crt_time timestamp not null);  -- All partition columns must contain the NOT NULL constraint.  
    CREATE TABLE
    
    Insert a large amount of test data to simulate a primary table that already contains data.
    postgres=# insert into part_test select id,md5(random()::text),clock_timestamp() + (id||' hour')::interval from generate_series(1,10000) t(id); 
    INSERT 0 10000
    postgres=# select * from part_test limit 10;                    
     id |               info               |          crt_time          
    ----+----------------------------------+----------------------------
      1 | 36fe1adedaa5b848caec4941f87d443a | 2016-10-25 10:27:13.206713
      2 | c7d7358e196a9180efb4d0a10269c889 | 2016-10-25 11:27:13.206893
      3 | 005bdb063550579333264b895df5b75e | 2016-10-25 12:27:13.206904
      4 | 6c900a0fc50c6e4da1ae95447c89dd55 | 2016-10-25 13:27:13.20691
      5 | 857214d8999348ed3cb0469b520dc8e5 | 2016-10-25 14:27:13.206916
      6 | 4495875013e96e625afbf2698124ef5b | 2016-10-25 15:27:13.206921
      7 | 82488cf7e44f87d9b879c70a9ed407d4 | 2016-10-25 16:27:13.20693
      8 | a0b92547c8f17f79814dfbb12b8694a0 | 2016-10-25 17:27:13.206936
      9 | 2ca09e0b85042b476fc235e75326b41b | 2016-10-25 18:27:13.206942
     10 | 7eb762e1ef7dca65faf413f236dff93d | 2016-10-25 19:27:13.206947
    (10 rows)
    
    Note:  
    1. All partition columns must contain the NOT NULL constraint.  
    2. The number of partitions must be sufficient to cover all existing records.  
    
    Create partitions and ensure that each partition contains one month of data  
    postgres=# select                                             
    create_range_partitions('part_test'::regclass,             -- The OID of the primary table.
                            'crt_time',                        -- The column name of the partition.
                            '2016-10-25 00:00:00'::timestamp,  -- The start value.
                            interval '1 month',                -- The interval of the interval type, applicable to ingestion-time partitioned tables.
                            24,                                -- The number of partitions.
                            false) ;                           -- The data is not migrated.
    NOTICE:  sequence "part_test_seq" does not exist, skipping
     create_range_partitions 
    -------------------------
                          24
    (1 row)
    postgres-# \d+ part_test
                                      Table "public.part_test"
      Column  |            Type             | Modifiers | Storage  | Stats target | Description 
    ----------+-----------------------------+-----------+----------+--------------+-------------
     id       | integer                     |           | plain    |              | 
     info     | text                        |           | extended |              | 
     crt_time | timestamp without time zone | not null  | plain    |              | 
    Child tables: part_test_1,
                  part_test_10,
                  part_test_11,
                  part_test_12,
                  part_test_13,
                  part_test_14,
                  part_test_15,
                  part_test_16,
                  part_test_17,
                  part_test_18,
                  part_test_19,
                  part_test_2,
                  part_test_20,
                  part_test_21,
                  part_test_22,
                  part_test_23,
                  part_test_24,
                  part_test_3,
                  part_test_4,
                  part_test_5,
                  part_test_6,
                  part_test_7,
                  part_test_8,
                  part_test_9
    
    
    The data is still in the primary table because it is not migrated.
    postgres=# select count(*) from only part_test;
     count 
    -------
     10000
    (1 row)
    
    
    Run non-blocking data migration.  
    partition_table_concurrently(relation   REGCLASS,              -- The OID of the primary table.
                                 batch_size INTEGER DEFAULT 1000,  -- The number of records to copy from the primary table at a time.
                                 sleep_time FLOAT8 DEFAULT 1.0)    -- The time interval between migration attempts if one or more rows in the batch are locked by other queries. pg_pathman waits for the specified time and tries again up to 60 times before quitting.
    
    
    postgres=# select partition_table_concurrently('part_test'::regclass,
                                 10000,
                                 1.0);
    NOTICE:  worker started, you can stop it with the following command: select stop_concurrent_part_task('part_test');
     partition_table_concurrently 
    ------------------------------
    
    (1 row)
    
    
    After the migration, all data is migrated to the partitions, and the primary table is empty.
    postgres=# select count(*) from only part_test;
     count 
    -------
         0
    (1 row)
    
    
    After the data is migrated, we recommend that you disable the primary table so that the primary table will not be included in the execution plan.
    postgres=# select set_enable_parent('part_test'::regclass, false);
     set_enable_parent 
    -------------------
    
    (1 row)
    
    postgres=# explain select * from part_test where crt_time = '2016-10-25 00:00:00'::timestamp;
                                       QUERY PLAN                                    
    ---------------------------------------------------------------------------------
     Append  (cost=0.00..16.18 rows=1 width=45)
       ->  Seq Scan on part_test_1  (cost=0.00..16.18 rows=1 width=45)
             Filter: (crt_time = '2016-10-25 00:00:00'::timestamp without time zone)
    (3 rows)
    範囲分割を使用する場合は、以下の点にご注意ください。
    • すべてのパーティション列が NOT NULL 制約付きである必要があります。
    • 既存のすべてのレコードに十分対応できるパーティション数とする必要があります。
    • ノンブロッキングデータ移行を実行します。
    • データ移行の完了後、プライマリテーブルを無効化します。
  2. ハッシュ分割
    ハッシュパーティションの作成には、管理関数を使用します。 開始値、間隔、およびパーティション数を指定できます。以下に例を示します。
    create_hash_partitions(relation         REGCLASS,  -- The OID of the primary table.
                           attribute        TEXT,      -- The column name of the partition.
                           partitions_count INTEGER,   -- The number of partitions to be created.
                           partition_data   BOOLEAN DEFAULT TRUE)   --  Specifies whether to immediately migrate data from the primary table to partitions. We recommend that you call the partition_table_concurrently() function to run non-blocking data migration.
    例:
    Create a primary table that needs to be partitioned.
    postgres=# create table part_test(id int, info text, crt_time timestamp not null);    -- All partition columns must contain the NOT NULL constraint.  
    CREATE TABLE
    
    Insert a large amount of test data to simulate a primary table that already contains data.
    postgres=# insert into part_test select id,md5(random()::text),clock_timestamp() + (id||' hour')::interval from generate_series(1,10000) t(id); 
    INSERT 0 10000
    postgres=# select * from part_test limit 10;   
     id |               info               |          crt_time          
    ----+----------------------------------+----------------------------
      1 | 29ce4edc70dbfbe78912beb7c4cc95c2 | 2016-10-25 10:47:32.873879
      2 | e0990a6fb5826409667c9eb150fef386 | 2016-10-25 11:47:32.874048
      3 | d25f577a01013925c203910e34470695 | 2016-10-25 12:47:32.874059
      4 | 501419c3f7c218e562b324a1bebfe0ad | 2016-10-25 13:47:32.874065
      5 | 5e5e22bdf110d66a5224a657955ba158 | 2016-10-25 14:47:32.87407
      6 | 55d2d4fd5229a6595e0dd56e13d32be4 | 2016-10-25 15:47:32.874076
      7 | 1dfb9a783af55b123c7a888afe1eb950 | 2016-10-25 16:47:32.874081
      8 | 41eeb0bf395a4ab1e08691125ae74bff | 2016-10-25 17:47:32.874087
      9 | 83783d69cc4f9bb41a3978fe9e13d7fa | 2016-10-25 18:47:32.874092
     10 | affc9406d5b3412ae31f7d7283cda0dd | 2016-10-25 19:47:32.874097
    (10 rows)
    
    Note:  
    1. All partition columns must contain the NOT NULL constraint.  
    
    Create 128 partitions
    postgres=# select                                             
    create_hash_partitions('part_test'::regclass, -- The OID of the primary table.
                            'crt_time',                        -- The column name of the partition.
                            128,                               -- The number of partitions to be created.
                            false) ;                           -- The data is not migrated.
     create_hash_partitions 
    ------------------------
                        128
    (1 row)
    
    postgres=# \d+ part_test
                                      Table "public.part_test"
      Column  |            Type             | Modifiers | Storage  | Stats target | Description 
    ----------+-----------------------------+-----------+----------+--------------+-------------
     id       | integer                     |           | plain    |              | 
     info     | text                        |           | extended |              | 
     crt_time | timestamp without time zone | not null  | plain    |              | 
    Child tables: part_test_0,
                  part_test_1,
                  part_test_10,
                  part_test_100,
                  part_test_101,
                  part_test_102,
                  part_test_103,
                  part_test_104,
                  part_test_105,
                  part_test_106,
                  part_test_107,
                  part_test_108,
                  part_test_109,
                  part_test_11,
                  part_test_110,
                  part_test_111,
                  part_test_112,
                  part_test_113,
                  part_test_114,
                  part_test_115,
                  part_test_116,
                  part_test_117,
                  part_test_118,
                  part_test_119,
                  part_test_12,
                  part_test_120,
                  part_test_121,
                  part_test_122,
                  part_test_123,
                  part_test_124,
                  part_test_125,
                  part_test_126,
                  part_test_127,
                  part_test_13,
                  part_test_14,
                  part_test_15,
                  part_test_16,
                  part_test_17,
                  part_test_18,
                  part_test_19,
                  part_test_2,
                  part_test_20,
                  part_test_21,
                  part_test_22,
                  part_test_23,
                  part_test_24,
                  part_test_25,
                  part_test_26,
                  part_test_27,
                  part_test_28,
                  part_test_29,
                  part_test_3,
                  part_test_30,
                  part_test_31,
                  part_test_32,
                  part_test_33,
                  part_test_34,
                  part_test_35,
                  part_test_36,
                  part_test_37,
                  part_test_38,
                  part_test_39,
                  part_test_4,
                  part_test_40,
                  part_test_41,
                  part_test_42,
                  part_test_43,
                  part_test_44,
                  part_test_45,
                  part_test_46,
                  part_test_47,
                  part_test_48,
                  part_test_49,
                  part_test_5,
                  part_test_50,
                  part_test_51,
                  part_test_52,
                  part_test_53,
                  part_test_54,
                  part_test_55,
                  part_test_56,
                  part_test_57,
                  part_test_58,
                  part_test_59,
                  part_test_6,
                  part_test_60,
                  part_test_61,
                  part_test_62,
                  part_test_63,
                  part_test_64,
                  part_test_65,
                  part_test_66,
                  part_test_67,
                  part_test_68,
                  part_test_69,
                  part_test_7,
                  part_test_70,
                  part_test_71,
                  part_test_72,
                  part_test_73,
                  part_test_74,
                  part_test_75,
                  part_test_76,
                  part_test_77,
                  part_test_78,
                  part_test_79,
                  part_test_8,
                  part_test_80,
                  part_test_81,
                  part_test_82,
                  part_test_83,
                  part_test_84,
                  part_test_85,
                  part_test_86,
                  part_test_87,
                  part_test_88,
                  part_test_89,
                  part_test_9,
                  part_test_90,
                  part_test_91,
                  part_test_92,
                  part_test_93,
                  part_test_94,
                  part_test_95,
                  part_test_96,
                  part_test_97,
                  part_test_98,
                  part_test_99
    
    
    The data is still in the primary table because it is not migrated.
    postgres=# select count(*) from only part_test;
     count 
    -------
     10000
    (1 row)
    
    
    Run non-blocking data migration  
    partition_table_concurrently(relation   REGCLASS,              -- The OID of the primary table.
                                 batch_size INTEGER DEFAULT 1000,  -- The number of records to copy from the primary table at a time.
                                 sleep_time FLOAT8 DEFAULT 1.0)    -- The time interval between migration attempts if one or more rows in the batch are locked by other queries. pg_pathman waits for the specified time and tries again up to 60 times before quitting.
    
    
    postgres=# select partition_table_concurrently('part_test'::regclass,
                                 10000,
                                 1.0);
    NOTICE:  worker started, you can stop it with the following command: select stop_concurrent_part_task('part_test');
     partition_table_concurrently 
    ------------------------------
    
    (1 row)
    
    
    After the migration, all data is migrated to the partitions, and the primary table is empty.
    postgres=# select count(*) from only part_test;
     count 
    -------
         0
    (1 row)
    
    
    After the data is migrated, we recommend that you disable the primary table so that the primary table will not be included in the execution plan.
    postgres=# select set_enable_parent('part_test'::regclass, false);
     set_enable_parent 
    -------------------
    
    (1 row)
    
    Query only a single partition.
    postgres=# explain select * from part_test where crt_time = '2016-10-25 00:00:00'::timestamp;
                                       QUERY PLAN                                    
    ---------------------------------------------------------------------------------
     Append  (cost=0.00..1.91 rows=1 width=45)
       ->  Seq Scan on part_test_122  (cost=0.00..1.91 rows=1 width=45)
             Filter: (crt_time = '2016-10-25 00:00:00'::timestamp without time zone)
    (3 rows)
    
    The constraints on partitions are as follows:  
    pg_pathman automatically completes the conversion. For traditional inheritance, expressions similar to select * from part_test where crt_time = '2016-10-25 00:00:00'::timestamp; cannot filter partitions.  
    postgres=# \d+ part_test_122
                                    Table "public.part_test_122"
      Column  |            Type             | Modifiers | Storage  | Stats target | Description 
    ----------+-----------------------------+-----------+----------+--------------+-------------
     id       | integer                     |           | plain    |              | 
     info     | text                        |           | extended |              | 
     crt_time | timestamp without time zone | not null  | plain    |              | 
    Check constraints:
        "pathman_part_test_122_3_check" CHECK (get_hash_part_idx(timestamp_hash(crt_time), 128) = 122)
    Inherits: part_test
    ハッシュパーティションを使用する場合は、以下の点に注意してください。
    • すべてのパーティション列は NOT NULL 制約付きである必要があります。
    • ノンブロッキングデータ移行を実行します。
    • データ移行の完了後、プライマリテーブルを無効化する必要があります。
    • pg_pathman は式の対象ではありません。 そのため、ハッシュパーティションの作成にはコマンド select * from part_test where crt_time = '2016-10-25 00:00:00'::timestamp; も使用できます。
    • ハッシュパーティション列は、int 型の列に限定されません。 列の型はハッシュ関数によって自動的に変換されます。
  3. データをパーティションに移行する
    パーティションの作成時にプライマリテーブルのデータがパーティションに移行されない場合、非ブロッキング移行関数を呼び出すことにより、データをパーティションに移行できます。 以下のコマンドを実行します。
    with tmp as (delete from a primary table limit xx nowait returning *) insert into a partition select * from tmp
    
    You can also use select array_agg(ctid) from a primary table limit xx for update nowati. Then execute the DELETE and INSERT statements.
    関数は以下のとおりです。
    partition_table_concurrently(relation   REGCLASS,              -- The OID of the primary table.
                                 batch_size INTEGER DEFAULT 1000, -- The number of records to copy from the primary table at a time.
                                 sleep_time FLOAT8 DEFAULT 1.0)    -- The time interval between migration attempts if one or more rows in the batch are locked by other queries. pg_pathman waits for the specified time and tries again up to 60 times before quitting.
    例:
    postgres=# select partition_table_concurrently('part_test'::regclass,
                                 10000,
                                 1.0);
    NOTICE:  worker started, you can stop it with the following command: select stop_concurrent_part_task('part_test');
     partition_table_concurrently 
    ------------------------------
    
    (1 row)
    移行タスクを停止するには、以下の関数を呼び出します。
    stop_concurrent_part_task(relation REGCLASS)
    バックグラウンドで実行されているデータ移行タスクを確認します。
    postgres=# select * from pathman_concurrent_part_tasks;
     userid | pid | dbid | relid | processed | status 
    --------+-----+------+-------+-----------+--------
    (0 rows)
  4. 範囲パーティションの分割
    パーティションが大きくなったため 2 つのパーティションに分割する場合は、以下の方法を使用します (範囲パーティションのみサポートされています)。
    split_range_partition(partition      REGCLASS,            -- The OID of the partition.
                          split_value    ANYELEMENT,          -- The split value.
                          partition_name TEXT DEFAULT NULL)   -- The name of the new partition.
    例:
    postgres=# \d+ part_test
                                      Table "public.part_test"
      Column  |            Type             | Modifiers | Storage  | Stats target | Description 
    ----------+-----------------------------+-----------+----------+--------------+-------------
     id       | integer                     |           | plain    |              | 
     info     | text                        |           | extended |              | 
     crt_time | timestamp without time zone | not null  | plain    |              | 
    Child tables: part_test_1,
                  part_test_10,
                  part_test_11,
                  part_test_12,
                  part_test_13,
                  part_test_14,
                  part_test_15,
                  part_test_16,
                  part_test_17,
                  part_test_18,
                  part_test_19,
                  part_test_2,
                  part_test_20,
                  part_test_21,
                  part_test_22,
                  part_test_23,
                  part_test_24,
                  part_test_3,
                  part_test_4,
                  part_test_5,
                  part_test_6,
                  part_test_7,
                  part_test_8,
                  part_test_9
    
    postgres=# \d+ part_test_1
                                     Table "public.part_test_1"
      Column  |            Type             | Modifiers | Storage  | Stats target | Description 
    ----------+-----------------------------+-----------+----------+--------------+-------------
     id       | integer                     |           | plain    |              | 
     info     | text                        |           | extended |              | 
     crt_time | timestamp without time zone | not null  | plain    |              | 
    Check constraints:
        "pathman_part_test_1_3_check" CHECK (crt_time >= '2016-10-25 00:00:00'::timestamp without time zone AND crt_time < '2016-11-25 00:00:00'::timestamp without time zone)
    Inherits: part_test
    分割
    postgres=# select split_range_partition('part_test_1'::regclass,              -- The OID of the partition.
                          '2016-11-10 00:00:00'::timestamp,     -- The split value.
                          'part_test_1_2');                     -- The name of the partitioned table.
                 split_range_partition             
    -----------------------------------------------
     {"2016-10-25 00:00:00","2016-11-25 00:00:00"}
    (1 row)
    分割によって作成される 2 つのテーブルは以下のとおりです。
    postgres=# \d+ part_test_1
                                     Table "public.part_test_1"
      Column  |            Type             | Modifiers | Storage  | Stats target | Description 
    ----------+-----------------------------+-----------+----------+--------------+-------------
     id       | integer                     |           | plain    |              | 
     info     | text                        |           | extended |              | 
     crt_time | timestamp without time zone | not null  | plain    |              | 
    Check constraints:
        "pathman_part_test_1_3_check" CHECK (crt_time >= '2016-10-25 00:00:00'::timestamp without time zone AND crt_time < '2016-11-10 00:00:00'::timestamp without time zone)
    Inherits: part_test
    
    postgres=# \d+ part_test_1_2 
                                    Table "public.part_test_1_2"
      Column  |            Type             | Modifiers | Storage  | Stats target | Description 
    ----------+-----------------------------+-----------+----------+--------------+-------------
     id       | integer                     |           | plain    |              | 
     info     | text                        |           | extended |              | 
     crt_time | timestamp without time zone | not null  | plain    |              | 
    Check constraints:
        "pathman_part_test_1_2_3_check" CHECK (crt_time >= '2016-11-10 00:00:00'::timestamp without time zone AND crt_time < '2016-11-25 00:00:00'::timestamp without time zone)
    Inherits: part_test
    データは自動的に他のパーティションに移行されます。
    postgres=# select count(*) from part_test_1;
     count 
    -------
       373
    (1 row)
    
    postgres=# select count(*) from part_test_1_2;
     count 
    -------
       360
    (1 row)
    継承関係は以下のとおりです。
    postgres=# \d+ part_test
                                      Table "public.part_test"
      Column  |            Type             | Modifiers | Storage  | Stats target | Description 
    ----------+-----------------------------+-----------+----------+--------------+-------------
     id       | integer                     |           | plain    |              | 
     info     | text                        |           | extended |              | 
     crt_time | timestamp without time zone | not null  | plain    |              | 
    Child tables: part_test_1,
                  part_test_10,
                  part_test_11,
                  part_test_12,
                  part_test_13,
                  part_test_14,
                  part_test_15,
                  part_test_16,
                  part_test_17,
                  part_test_18,
                  part_test_19,
                  part_test_1_2,    -- The added table.
                  part_test_2,
                  part_test_20,
                  part_test_21,
                  part_test_22,
                  part_test_23,
                  part_test_24,
                  part_test_3,
                  part_test_4,
                  part_test_5,
                  part_test_6,
                  part_test_7,
                  part_test_8,
                  part_test_9
  5. 範囲パーティションのマージ
    範囲パーティションのみサポートされています。 以下の関数を呼び出します。
    Specify two partitions to be merged, which must be adjacent partitions.  
    merge_range_partitions(partition1 REGCLASS, partition2 REGCLASS)
    例:
    postgres=# select merge_range_partitions('part_test_2'::regclass, 'part_test_12'::regclass) ;
    ERROR:  merge failed, partitions must be adjacent
    CONTEXT:  PL/pgSQL function merge_range_partitions_internal(regclass,regclass,regclass,anyelement) line 27 at RAISE
    SQL statement "SELECT public.merge_range_partitions_internal($1, $2, $3, NULL::timestamp without time zone)"
    PL/pgSQL function merge_range_partitions(regclass,regclass) line 44 at EXECUTE
    An error is returned because the partitions are not adjacent.
    
    Adjacent partitions can be merged.
    postgres=# select merge_range_partitions('part_test_1'::regclass, 'part_test_1_2'::regclass) ;
     merge_range_partitions 
    ------------------------
    
    (1 row)
    マージが完了すると、パーティションの 1 つが削除されます。
    postgres=# \d part_test_1_2
    Did not find any relation named "part_test_1_2".
    
    postgres=# \d part_test_1
                 Table "public.part_test_1"
      Column  |            Type             | Modifiers 
    ----------+-----------------------------+-----------
     id       | integer                     | 
     info     | text                        | 
     crt_time | timestamp without time zone | not null
    Check constraints:
        "pathman_part_test_1_3_check" CHECK (crt_time >= '2016-10-25 00:00:00'::timestamp without time zone AND crt_time < '2016-11-25 00:00:00'::timestamp without time zone)
    Inherits: part_test
    
    postgres=# select count(*) from part_test_1;
     count 
    -------
       733
    (1 row)
  6. 最後のパーティションの後にパーティションを追加する

    以前にパーティション分割されたプライマリテーブルにパーティションを追加するには、いくつかの方法があります。 最後のパーティションの後にパーティションを追加する方法もそのひとつです。

    新しいパーティションが追加されると、以前に分割されたテーブルの間隔が使用されます。 pathman_config コマンドを実行して、パーティション分割テーブルを初めて作成したときの間隔を照会できます。
    postgres=# select * from pathman_config;
      partrel  | attname  | parttype | range_interval 
    -----------+----------+----------+----------------
     part_test | crt_time |        2 | 1 mon
    (1 row)
    新しい範囲パーティションを追加します (テーブルスペースは指定できません)。
    append_range_partition(parent         REGCLASS,            -- The OID of the primary table.
                           partition_name TEXT DEFAULT NULL,   -- (Optional) The name of the new partition. Default value: null.
                           tablespace     TEXT DEFAULT NULL)   -- (Optional) The tablespace where the new partition is stored. Default value: null.
    例:
    postgres=# select append_range_partition('part_test'::regclass);
     append_range_partition 
    ------------------------
     public.part_test_25
    (1 row)
    
    postgres=# \d+ part_test_25
                                    Table "public.part_test_25"
      Column  |            Type             | Modifiers | Storage  | Stats target | Description 
    ----------+-----------------------------+-----------+----------+--------------+-------------
     id       | integer                     |           | plain    |              | 
     info     | text                        |           | extended |              | 
     crt_time | timestamp without time zone | not null  | plain    |              | 
    Check constraints:
        "pathman_part_test_25_3_check" CHECK (crt_time >= '2018-10-25 00:00:00'::timestamp without time zone AND crt_time < '2018-11-25 00:00:00'::timestamp without time zone)
    Inherits: part_test
    
    postgres=# \d+ part_test_24
                                    Table "public.part_test_24"
      Column  |            Type             | Modifiers | Storage  | Stats target | Description 
    ----------+-----------------------------+-----------+----------+--------------+-------------
     id       | integer                     |           | plain    |              | 
     info     | text                        |           | extended |              | 
     crt_time | timestamp without time zone | not null  | plain    |              | 
    Check constraints:
        "pathman_part_test_24_3_check" CHECK (crt_time >= '2018-09-25 00:00:00'::timestamp without time zone AND crt_time < '2018-10-25 00:00:00'::timestamp without time zone)
    Inherits: part_test
  7. パーティションの先頭に範囲パーティションを追加する
    パーティションの先頭にパーティションを追加します。 関数は以下のとおりです。
    prepend_range_partition(parent         REGCLASS,
                            partition_name TEXT DEFAULT NULL,
                            tablespace     TEXT DEFAULT NULL)
    例:
    postgres=# select prepend_range_partition('part_test'::regclass);
     prepend_range_partition 
    -------------------------
     public.part_test_26
    (1 row)
    
    postgres=# \d+ part_test_26
                                    Table "public.part_test_26"
      Column  |            Type             | Modifiers | Storage  | Stats target | Description 
    ----------+-----------------------------+-----------+----------+--------------+-------------
     id       | integer                     |           | plain    |              | 
     info     | text                        |           | extended |              | 
     crt_time | timestamp without time zone | not null  | plain    |              | 
    Check constraints:
        "pathman_part_test_26_3_check" CHECK (crt_time >= '2016-09-25 00:00:00'::timestamp without time zone AND crt_time < '2016-10-25 00:00:00'::timestamp without time zone)
    Inherits: part_test
    
    postgres=# \d+ part_test_1
                                     Table "public.part_test_1"
      Column  |            Type             | Modifiers | Storage  | Stats target | Description 
    ----------+-----------------------------+-----------+----------+--------------+-------------
     id       | integer                     |           | plain    |              | 
     info     | text                        |           | extended |              | 
     crt_time | timestamp without time zone | not null  | plain    |              | 
    Check constraints:
        "pathman_part_test_1_3_check" CHECK (crt_time >= '2016-10-25 00:00:00'::timestamp without time zone AND crt_time < '2016-11-25 00:00:00'::timestamp without time zone)
    Inherits: part_test
  8. パーティションを追加する
    パーティションの開始値を指定して、新しいパーティションを作成できます。 範囲が既存のパーティションと重複しない場合は、新しいパーティションを作成できます。 この方法では、非連続パーティションを作成できます。 たとえば、既存のパーティションの範囲が2010 から 2015の場合でも、2020から新しいパーティションを作成できます。 2015 から 2020 の間のパーティションを作成する必要はありません。 関数は以下のとおりです。
    add_range_partition(relation       REGCLASS,    -- The OID of the primary table.
                        start_value    ANYELEMENT,  -- The start value.
                        end_value      ANYELEMENT,  -- The end value.
                        partition_name TEXT DEFAULT NULL,  -- The name of the partition.
                        tablespace TEXT DEFAULT NULL) -- The name of the tablespace in which a partition resides.
    例:
    postgres=# select add_range_partition('part_test'::regclass,    -- The OID of the primary table.
                        '2020-01-01 00:00:00'::timestamp,  -- The start value.
                        '2020-02-01 00:00:00'::timestamp); -- The end value.
     add_range_partition 
    ---------------------
     public.part_test_27
    (1 row)
    
    postgres=# \d+ part_test_27
                                    Table "public.part_test_27"
      Column  |            Type             | Modifiers | Storage  | Stats target | Description 
    ----------+-----------------------------+-----------+----------+--------------+-------------
     id       | integer                     |           | plain    |              | 
     info     | text                        |           | extended |              | 
     crt_time | timestamp without time zone | not null  | plain    |              | 
    Check constraints:
        "pathman_part_test_27_3_check" CHECK (crt_time >= '2020-01-01 00:00:00'::timestamp without time zone AND crt_time < '2020-02-01 00:00:00'::timestamp without time zone)
    Inherits: part_test
  9. パーティションを削除する
    単一のパーティション範囲を削除するには、以下の関数を呼び出します。
    drop_range_partition(partition TEXT,   -- The name of the partition to be deleted.
                        delete_data BOOLEAN DEFAULT TRUE) -- Specifies whether to delete the data of the partition. If you set the value to FALSE, the data of the partition is migrated to the primary table.  
    
    Drop RANGE partition and all of its data if delete_data is true.
    例:
    Delete a partition and migrate data of the partition to the primary table.  
    postgres=# select drop_range_partition('part_test_1',false);
    NOTICE:  733 rows copied from part_test_1
     drop_range_partition 
    ----------------------
     part_test_1
    (1 row)
    
    postgres=# select drop_range_partition('part_test_2',false);
    NOTICE:  720 rows copied from part_test_2
     drop_range_partition 
    ----------------------
     part_test_2
    (1 row)
    
    postgres=# select count(*) from part_test;
     count 
    -------
     10000
    (1 row)
    
    Delete a partition and the data of the partition without migrating the data to the primary table.  
    postgres=# select drop_range_partition('part_test_3',true);
     drop_range_partition 
    ----------------------
     part_test_3
    (1 row)
    
    postgres=# select count(*) from part_test;
     count 
    -------
      9256
    (1 row)
    
    postgres=# select count(*) from only part_test;
     count 
    -------
      1453
    (1 row)
    すべてのパーティションを削除し、データをプライマリテーブルに移行するかどうかを指定します。 関数は以下のとおりです。
    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.
    例:
    postgres=# select drop_partitions('part_test'::regclass, false);  -- Delete all partitions and migrate the data to the primary table.
    NOTICE:  function public.part_test_upd_trig_func() does not exist, skipping
    NOTICE:  744 rows copied from part_test_4
    NOTICE:  672 rows copied from part_test_5
    NOTICE:  744 rows copied from part_test_6
    NOTICE:  720 rows copied from part_test_7
    NOTICE:  744 rows copied from part_test_8
    NOTICE:  720 rows copied from part_test_9
    NOTICE:  744 rows copied from part_test_10
    NOTICE:  744 rows copied from part_test_11
    NOTICE:  720 rows copied from part_test_12
    NOTICE:  744 rows copied from part_test_13
    NOTICE:  507 rows copied from part_test_14
    NOTICE:  0 rows copied from part_test_15
    NOTICE:  0 rows copied from part_test_16
    NOTICE:  0 rows copied from part_test_17
    NOTICE:  0 rows copied from part_test_18
    NOTICE:  0 rows copied from part_test_19
    NOTICE:  0 rows copied from part_test_20
    NOTICE:  0 rows copied from part_test_21
    NOTICE:  0 rows copied from part_test_22
    NOTICE:  0 rows copied from part_test_23
    NOTICE:  0 rows copied from part_test_24
    NOTICE:  0 rows copied from part_test_25
    NOTICE:  0 rows copied from part_test_26
    NOTICE:  0 rows copied from part_test_27
     drop_partitions 
    -----------------
                  24
    (1 row)
    
    postgres=# select count(*) from part_test;
     count 
    -------
      9256
    (1 row)
    
    postgres=# \dt part_test_4
    No matching relations found.
  10. テーブルをパーティション分割テーブルにアタッチする
    テーブルをパーティション分割されたプライマリテーブルにアタッチします。 テーブルには、削除された列を含め、プライマリテーブルと同じスキーマが必要です (pg_attributeの整合性を確認してください)。 関数は以下のとおりです。
    attach_range_partition(relation    REGCLASS,    -- The OID of the primary table.
                           partition   REGCLASS,    -- The OID of the partition table.
                           start_value ANYELEMENT,  -- The start value.
                           end_value   ANYELEMENT)  -- The start value.
    例:
    postgres=# create table part_test_1 (like part_test including all);
    CREATE TABLE
    postgres=# \d+ part_test
                                      Table "public.part_test"
      Column  |            Type             | Modifiers | Storage  | Stats target | Description 
    ----------+-----------------------------+-----------+----------+--------------+-------------
     id       | integer                     |           | plain    |              | 
     info     | text                        |           | extended |              | 
     crt_time | timestamp without time zone | not null  | plain    |              | 
    
    postgres=# \d+ part_test_1
                                     Table "public.part_test_1"
      Column  |            Type             | Modifiers | Storage  | Stats target | Description 
    ----------+-----------------------------+-----------+----------+--------------+-------------
     id       | integer                     |           | plain    |              | 
     info     | text                        |           | extended |              | 
     crt_time | timestamp without time zone | not null  | plain    |              | 
    
    postgres=# select attach_range_partition('part_test'::regclass, 'part_test_1'::regclass, '2019-01-01 00:00:00'::timestamp, '2019-02-01 00:00:00'::timestamp);
     attach_range_partition 
    ------------------------
     part_test_1
    (1 row)
    
    When the table is attached,
    inheritance relationships and constraints are created automatically.  
    postgres=# \d+ part_test_1
                                     Table "public.part_test_1"
      Column  |            Type             | Modifiers | Storage  | Stats target | Description 
    ----------+-----------------------------+-----------+----------+--------------+-------------
     id       | integer                     |           | plain    |              | 
     info     | text                        |           | extended |              | 
     crt_time | timestamp without time zone | not null  | plain    |              | 
    Check constraints:
        "pathman_part_test_1_3_check" CHECK (crt_time >= '2019-01-01 00:00:00'::timestamp without time zone AND crt_time < '2019-02-01 00:00:00'::timestamp without time zone)
    Inherits: part_test
  11. プライマリテーブルからパーティションをデタッチする (パーティションを通常のテーブルに変換する)
    プライマリテーブルの継承からパーティションを削除します。 データは削除されません。 継承と制約が削除されます。 関数は以下のとおりです。
    detach_range_partition(partition REGCLASS)  -- Specify the name of the partition and convert the partition to a normal table.
    例:
    postgres=# select count(*) from part_test;
     count 
    -------
      9256
    (1 row)
    
    postgres=# select count(*) from part_test_2;
     count 
    -------
       733
    (1 row)
    
    postgres=# select detach_range_partition('part_test_2');
     detach_range_partition 
    ------------------------
     part_test_2
    (1 row)
    
    postgres=# select count(*) from part_test_2;
     count 
    -------
       733
    (1 row)
    
    postgres=# select count(*) from part_test;
     count 
    -------
      8523
    (1 row)
  12. パーティション分割テーブルのpg_pathman プラグインを永続的に無効にする
    単一の分割されたプライマリテーブルの pg_pathman プラグインを無効化できます。 関数は以下のとおりです。
    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.
    
    postgres=# \sf disable_pathman_for
    CREATE OR REPLACE FUNCTION public.disable_pathman_for(parent_relid regclass)
     RETURNS void
     LANGUAGE plpgsql
     STRICT
    AS $function$
    BEGIN
            PERFORM public.validate_relname(parent_relid);
    
            DELETE FROM public.pathman_config WHERE partrel = parent_relid;
            PERFORM public.drop_triggers(parent_relid);
    
            /* Notify backend about changes */
            PERFORM public.on_remove_partitions(parent_relid);
    END
    $function$
    例:
    postgres=# select disable_pathman_for('part_test');
    NOTICE:  drop cascades to 23 other objects
    DETAIL:  drop cascades to trigger part_test_upd_trig on table part_test_3
    drop cascades to trigger part_test_upd_trig on table part_test_4
    drop cascades to trigger part_test_upd_trig on table part_test_5
    drop cascades to trigger part_test_upd_trig on table part_test_6
    drop cascades to trigger part_test_upd_trig on table part_test_7
    drop cascades to trigger part_test_upd_trig on table part_test_8
    drop cascades to trigger part_test_upd_trig on table part_test_9
    drop cascades to trigger part_test_upd_trig on table part_test_10
    drop cascades to trigger part_test_upd_trig on table part_test_11
    drop cascades to trigger part_test_upd_trig on table part_test_12
    drop cascades to trigger part_test_upd_trig on table part_test_13
    drop cascades to trigger part_test_upd_trig on table part_test_14
    drop cascades to trigger part_test_upd_trig on table part_test_15
    drop cascades to trigger part_test_upd_trig on table part_test_16
    drop cascades to trigger part_test_upd_trig on table part_test_17
    drop cascades to trigger part_test_upd_trig on table part_test_18
    drop cascades to trigger part_test_upd_trig on table part_test_19
    drop cascades to trigger part_test_upd_trig on table part_test_20
    drop cascades to trigger part_test_upd_trig on table part_test_21
    drop cascades to trigger part_test_upd_trig on table part_test_22
    drop cascades to trigger part_test_upd_trig on table part_test_23
    drop cascades to trigger part_test_upd_trig on table part_test_24
    drop cascades to trigger part_test_upd_trig on table part_test_25
     disable_pathman_for 
    ---------------------
    
    (1 row)
    
    postgres=# \d+ part_test
                                      Table "public.part_test"
      Column  |            Type             | Modifiers | Storage  | Stats target | Description 
    ----------+-----------------------------+-----------+----------+--------------+-------------
     id       | integer                     |           | plain    |              | 
     info     | text                        |           | extended |              | 
     crt_time | timestamp without time zone | not null  | plain    |              | 
    Child tables: part_test_10,
                  part_test_11,
                  part_test_12,
                  part_test_13,
                  part_test_14,
                  part_test_15,
                  part_test_16,
                  part_test_17,
                  part_test_18,
                  part_test_19,
                  part_test_20,
                  part_test_21,
                  part_test_22,
                  part_test_23,
                  part_test_24,
                  part_test_25,
                  part_test_26,
                  part_test_27,
                  part_test_28,
                  part_test_29,
                  part_test_3,
                  part_test_30,
                  part_test_31,
                  part_test_32,
                  part_test_33,
                  part_test_34,
                  part_test_35,
                  part_test_4,
                  part_test_5,
                  part_test_6,
                  part_test_7,
                  part_test_8,
                  part_test_9
    
    postgres=# \d+ part_test_10
                                    Table "public.part_test_10"
      Column  |            Type             | Modifiers | Storage  | Stats target | Description 
    ----------+-----------------------------+-----------+----------+--------------+-------------
     id       | integer                     |           | plain    |              | 
     info     | text                        |           | extended |              | 
     crt_time | timestamp without time zone | not null  | plain    |              | 
    Check constraints:
        "pathman_part_test_10_3_check" CHECK (crt_time >= '2017-06-25 00:00:00'::timestamp without time zone AND crt_time < '2017-07-25 00:00:00'::timestamp without time zone)
    Inherits: part_test
    pg_pathman プラグインを無効にしても、継承と制約は変更されません。 pg_pathman プラグインは、カスタムスキャン実行プランに介入しません。 pg_pathman プラグインを無効化した後の実行プラン:
    postgres=# explain select * from part_test where crt_time='2017-06-25 00:00:00'::timestamp;
                                       QUERY PLAN                                    
    ---------------------------------------------------------------------------------
     Append  (cost=0.00..16.00 rows=2 width=45)
       ->  Seq Scan on part_test  (cost=0.00..0.00 rows=1 width=45)
             Filter: (crt_time = '2017-06-25 00:00:00'::timestamp without time zone)
       ->  Seq Scan on part_test_10  (cost=0.00..16.00 rows=1 width=45)
             Filter: (crt_time = '2017-06-25 00:00:00'::timestamp without time zone)
    (5 rows)
    重要 disable_pathman_for は取り消しできません。 実行には注意が必要です。

高度なパーティション管理

  1. プライマリテーブルを無効化する
    プライマリテーブルの全データをパーティションに移行後、プライマリテーブルを無効にできます。 関数は以下のとおりです。
    set_enable_parent(relation REGCLASS, value BOOLEAN)
    
    
    Include/exclude parent table into/from query plan. 
    
    In original PostgreSQL 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.
    例:
    select set_enable_parent('part_test', false);
  2. 自動分割の継続
    自動分割の継続は、範囲パーティションテーブルでサポートされています。 挿入されたデータが既存のパーティションの範囲を超える場合、パーティションが自動的に作成されます。
    set_auto(relation REGCLASS, value BOOLEAN)
    
    Enable/disable auto partition propagation (only for RANGE partitioning). 
    
    It is enabled by default.
    例:
    postgres=# \d+ part_test
                                      Table "public.part_test"
      Column  |            Type             | Modifiers | Storage  | Stats target | Description 
    ----------+-----------------------------+-----------+----------+--------------+-------------
     id       | integer                     |           | plain    |              | 
     info     | text                        |           | extended |              | 
     crt_time | timestamp without time zone | not null  | plain    |              | 
    Child tables: part_test_10,
                  part_test_11,
                  part_test_12,
                  part_test_13,
                  part_test_14,
                  part_test_15,
                  part_test_16,
                  part_test_17,
                  part_test_18,
                  part_test_19,
                  part_test_20,
                  part_test_21,
                  part_test_22,
                  part_test_23,
                  part_test_24,
                  part_test_25,
                  part_test_26,
                  part_test_3,
                  part_test_4,
                  part_test_5,
                  part_test_6,
                  part_test_7,
                  part_test_8,
                  part_test_9
    
    postgres=# \d+ part_test_26
                                    Table "public.part_test_26"
      Column  |            Type             | Modifiers | Storage  | Stats target | Description 
    ----------+-----------------------------+-----------+----------+--------------+-------------
     id       | integer                     |           | plain    |              | 
     info     | text                        |           | extended |              | 
     crt_time | timestamp without time zone | not null  | plain    |              | 
    Check constraints:
        "pathman_part_test_26_3_check" CHECK (crt_time >= '2018-09-25 00:00:00'::timestamp without time zone AND crt_time < '2018-10-25 00:00:00'::timestamp without time zone)
    Inherits: part_test
    
    postgres=# \d+ part_test_25
                                    Table "public.part_test_25"
      Column  |            Type             | Modifiers | Storage  | Stats target | Description 
    ----------+-----------------------------+-----------+----------+--------------+-------------
     id       | integer                     |           | plain    |              | 
     info     | text                        |           | extended |              | 
     crt_time | timestamp without time zone | not null  | plain    |              | 
    Check constraints:
        "pathman_part_test_25_3_check" CHECK (crt_time >= '2018-08-25 00:00:00'::timestamp without time zone AND crt_time < '2018-09-25 00:00:00'::timestamp without time zone)
    Inherits: part_test
    
    When the inserted data is beyond the partitioning range, a large number of new partitions are created based on the interval when the primary table is partitioned.  
    postgres=# insert into part_test values (1,'test','2222-01-01'::timestamp);
    
    After the data is inserted, a large number of partitions are created because the range of the inserted values is too large.  
    
    postgres=# \d+ part_test
                                      Table "public.part_test"
      Column  |            Type             | Modifiers | Storage  | Stats target | Description 
    ----------+-----------------------------+-----------+----------+--------------+-------------
     id       | integer                     |           | plain    |              | 
     info     | text                        |           | extended |              | 
     crt_time | timestamp without time zone | not null  | plain    |              | 
    Child tables: part_test_10,
                  part_test_100,
                  part_test_1000,
                  part_test_1001,
            .....................................
            A large number of partitions
    不適切な自動連続分割は時間を浪費する可能性があるため、自動連続分割は無効化することを推奨します。
  3. パーティションの作成ごとにトリガーされるコールバック関数
    コールバック関数は、パーティションが作成されるたびに自動的にトリガーされる関数です。 たとえば、論理レプリケーションを実行してステートメントをテーブルに格納する DDL ステートメントをコールバック関数で記録できます。 コールバック関数は以下のとおりです。
    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"
    }
    例:
    Callback function  
    postgres=# create or replace function f_callback_test(jsonb) returns void as
    $$
    declare
    begin
      create table if not exists rec_part_ddl(id serial primary key, parent name, parttype int, partition name, range_max text, range_min text);
      if ($1->>'parttype')::int = 1 then
        raise notice 'parent: %, parttype: %, partition: %', $1->>'parent', $1->>'parttype', $1->>'partition';
        insert into rec_part_ddl(parent, parttype, partition) values (($1->>'parent')::name, ($1->>'parttype')::int, ($1->>'partition')::name);
      elsif ($1->>'parttype')::int = 2 then
        raise notice 'parent: %, parttype: %, partition: %, range_max: %, range_min: %', $1->>'parent', $1->>'parttype', $1->>'partition', $1->>'range_max', $1->>'range_min';
        insert into rec_part_ddl(parent, parttype, partition, range_max, range_min) values (($1->>'parent')::name, ($1->>'parttype')::int, ($1->>'partition')::name, $1->>'range_max', $1->>'range_min');
      end if;
    end;
    $$ language plpgsql strict;
    
    Test table
    postgres=# create table tt(id int, info text, crt_time timestamp not null);
    CREATE TABLE
    
    Set the callback function for the test table.
    select set_init_callback('tt'::regclass, 'f_callback_test'::regproc);
    
    Create a partition
    postgres=# select                                                          
    create_range_partitions('tt'::regclass,                    -- The OID of the primary table.
                            'crt_time',                        -- The column name of the partition.
                            '2016-10-25 00:00:00'::timestamp,  -- The start value.
                            interval '1 month',                -- The interval of the interval type, applicable to ingestion-time partitioned tables.
                            24,                                -- The number of partitions.
                            false) ;
     create_range_partitions 
    -------------------------
                          24
    (1 row)
    
    Check whether the callback function is called.  
    postgres=# select * from rec_part_ddl;
     id | parent | parttype | partition |      range_max      |      range_min      
    ----+--------+----------+-----------+---------------------+---------------------
      1 | tt     |        2 | tt_1      | 2016-11-25 00:00:00 | 2016-10-25 00:00:00
      2 | tt     |        2 | tt_2      | 2016-12-25 00:00:00 | 2016-11-25 00:00:00
      3 | tt     |        2 | tt_3      | 2017-01-25 00:00:00 | 2016-12-25 00:00:00
      4 | tt     |        2 | tt_4      | 2017-02-25 00:00:00 | 2017-01-25 00:00:00
      5 | tt     |        2 | tt_5      | 2017-03-25 00:00:00 | 2017-02-25 00:00:00
      6 | tt     |        2 | tt_6      | 2017-04-25 00:00:00 | 2017-03-25 00:00:00
      7 | tt     |        2 | tt_7      | 2017-05-25 00:00:00 | 2017-04-25 00:00:00
      8 | tt     |        2 | tt_8      | 2017-06-25 00:00:00 | 2017-05-25 00:00:00
      9 | tt     |        2 | tt_9      | 2017-07-25 00:00:00 | 2017-06-25 00:00:00
     10 | tt     |        2 | tt_10     | 2017-08-25 00:00:00 | 2017-07-25 00:00:00
     11 | tt     |        2 | tt_11     | 2017-09-25 00:00:00 | 2017-08-25 00:00:00
     12 | tt     |        2 | tt_12     | 2017-10-25 00:00:00 | 2017-09-25 00:00:00
     13 | tt     |        2 | tt_13     | 2017-11-25 00:00:00 | 2017-10-25 00:00:00
     14 | tt     |        2 | tt_14     | 2017-12-25 00:00:00 | 2017-11-25 00:00:00
     15 | tt     |        2 | tt_15     | 2018-01-25 00:00:00 | 2017-12-25 00:00:00
     16 | tt     |        2 | tt_16     | 2018-02-25 00:00:00 | 2018-01-25 00:00:00
     17 | tt     |        2 | tt_17     | 2018-03-25 00:00:00 | 2018-02-25 00:00:00
     18 | tt     |        2 | tt_18     | 2018-04-25 00:00:00 | 2018-03-25 00:00:00
     19 | tt     |        2 | tt_19     | 2018-05-25 00:00:00 | 2018-04-25 00:00:00
     20 | tt     |        2 | tt_20     | 2018-06-25 00:00:00 | 2018-05-25 00:00:00
     21 | tt     |        2 | tt_21     | 2018-07-25 00:00:00 | 2018-06-25 00:00:00
     22 | tt     |        2 | tt_22     | 2018-08-25 00:00:00 | 2018-07-25 00:00:00
     23 | tt     |        2 | tt_23     | 2018-09-25 00:00:00 | 2018-08-25 00:00:00
     24 | tt     |        2 | tt_24     | 2018-10-25 00:00:00 | 2018-09-25 00:00:00
    (24 rows)