こんにちは。サイオステクノロジー OSS サポート担当 Y です。
今回は PostgreSQL 11 (現時点ではまだ beta 版) の新機能である “デフォルトパーティション” を検証してみました。(※以下の内容は CentOS 7.5/PostgreSQL 10.5/PostgreSQL 11beta3 にて検証しています。)
■はじめに
昨年リリースされた PostgreSQL 10 の新機能である Declarative Partitioning には、いわゆる “デフォルトパーティション” の機能が存在していないのですが、PostgreSQL 11 ではこの “デフォルトパーティション” が実装される予定となっています。
今回は PostgreSQL 11beta3 を使って、このデフォルトパーティションを試してみようと思います。
■検証 (PostgreSQL 10 の動作確認)
まずは PostgreSQL 10 の動作を確認してみます。(以下の例では LIST パーティションを使用しています)
postgres=# CREATE TABLE hoge (list_key int, data text) PARTITION BY LIST (list_key); CREATE TABLE postgres=# CREATE TABLE hoge_child_1 PARTITION OF hoge FOR VALUES IN (1); CREATE TABLE postgres=# CREATE TABLE hoge_child_2 PARTITION OF hoge FOR VALUES IN (2); CREATE TABLE postgres=# CREATE TABLE hoge_child_3 PARTITION OF hoge FOR VALUES IN (3); CREATE TABLE postgres=# postgres=# \d+ hoge Table "public.hoge" Column | Type | Collation | Nullable | Default | Storage | Stats target | Description ----------+---------+-----------+----------+---------+----------+--------------+------------- list_key | integer | | | | plain | | data | text | | | | extended | | Partition key: LIST (list_key) Partitions: hoge_child_1 FOR VALUES IN (1), hoge_child_2 FOR VALUES IN (2), hoge_child_3 FOR VALUES IN (3)
上記の様にパーティショニングされたテーブルにて、”条件の範囲内” の値 (上記例の場合 “1”, “2”, “3”) を INSERT すると以下の様に正常に各子テーブルにレコードが振り分けられます。
postgres=# INSERT INTO hoge VALUES (1, 'hogehoge'), (2, 'hogehoge'), (3, 'hogehoge'); INSERT 0 3 postgres=# postgres=# SELECT * FROM hoge; list_key | data ----------+---------- 1 | hogehoge 2 | hogehoge 3 | hogehoge (3 rows) postgres=# postgres=# SELECT * FROM hoge_child_1; list_key | data ----------+---------- 1 | hogehoge (1 row) postgres=# postgres=# SELECT * FROM hoge_child_2; list_key | data ----------+---------- 2 | hogehoge (1 row) postgres=# postgres=# SELECT * FROM hoge_child_3; list_key | data ----------+---------- 3 | hogehoge (1 row)
しかし、PostgreSQL 10 で “条件の範囲外” の値 (上記例の場合 “1”, “2”, “3” 以外の値) を INSERT しようとすると、以下の様に ERROR になってしまいます。
postgres=# INSERT INTO hoge VALUES (4, 'hogehoge'); ERROR: no partition of relation "hoge" found for row DETAIL: Partition key of the failing row contains (list_key) = (4).
■検証 (PostgreSQL 11 の動作確認)
それでは、PostgreSQL 11beta3 でデフォルトパーティションを試してみます。
まずは、前述した PostgreSQL 10 の検証と同じテーブルを作成します。
postgres=# CREATE TABLE hoge (list_key int, data text) PARTITION BY LIST (list_key); CREATE TABLE postgres=# CREATE TABLE hoge_child_1 PARTITION OF hoge FOR VALUES IN (1); CREATE TABLE postgres=# CREATE TABLE hoge_child_2 PARTITION OF hoge FOR VALUES IN (2); CREATE TABLE postgres=# CREATE TABLE hoge_child_3 PARTITION OF hoge FOR VALUES IN (3); CREATE TABLE postgres=# postgres=# \d+ hoge Table "public.hoge" Column | Type | Collation | Nullable | Default | Storage | Stats target | Description ----------+---------+-----------+----------+---------+----------+--------------+------------- list_key | integer | | | | plain | | data | text | | | | extended | | Partition key: LIST (list_key) Partitions: hoge_child_1 FOR VALUES IN (1), hoge_child_2 FOR VALUES IN (2), hoge_child_3 FOR VALUES IN (3)
この状態で振り分け条件として設定していない値を INSERT すると PostgreSQL 10 と同じ様に ERROR になります。
postgres=# INSERT INTO hoge VALUES (4, 'hogehoge'); ERROR: no partition of relation "hoge" found for row DETAIL: Partition key of the failing row contains (list_key) = (4).
しかし、PostgreSQL 11 ではデフォルトパーティションを作成することができるため、テーブル “hoge” にデフォルトパーティションを追加してみます。デフォルトパーティションを作成する場合は、CREATE TABLE 文にて “DEFAULT” を指定します。
postgres=# CREATE TABLE hoge_child_default PARTITION OF hoge DEFAULT; CREATE TABLE postgres=# postgres=# \d+ hoge Table "public.hoge" Column | Type | Collation | Nullable | Default | Storage | Stats target | Description ----------+---------+-----------+----------+---------+----------+--------------+------------- list_key | integer | | | | plain | | data | text | | | | extended | | Partition key: LIST (list_key) Partitions: hoge_child_1 FOR VALUES IN (1), hoge_child_2 FOR VALUES IN (2), hoge_child_3 FOR VALUES IN (3), hoge_child_default DEFAULT
上記の様にデフォルトパーティションを追加した後に、改めて振り分け条件として設定していない値を INSERT すると、今度は ERROR にならずにデータを INSERT することができます。
postgres=# INSERT INTO hoge VALUES (4, 'hogehoge'); INSERT 0 1 postgres=# postgres=# SELECT * FROM hoge; list_key | data ----------+---------- 4 | hogehoge (1 row)
この状態で子テーブル “hoge_child_default” を確認してみると、list_key に “4” を指定したレコードが格納されていることが確認できます。
postgres=# SELECT * FROM hoge_child_default; list_key | data ----------+---------- 4 | hogehoge (1 row)
この様に、PostgreSQL 11 ではデフォルトパーティションを設定できるので、振り分け条件に合致しないレコードを INSERT した場合でも ERROR にならずにレコードを格納することができます。
■最後に
業務上規定された範囲外の値を INSERT しようとした場合には ERROR を返した方が良い等、デフォルトパーティションが不要な場合もあるとは思いますが、PostgreSQL 10 ではパーティションキーの値をアプリ側で厳密に管理する必要があったので、デフォルトパーティションが有用な場面も多いのではないでしょうか。
PostgreSQL 11 ではパーティション関連の機能を含め様々な機能が強化されているので、次回も PostgreSQL 11 の新機能の検証を実施してみようと思います。