他のバージョンの文書 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9.6 | 9.5 | 9.4 | 9.3 | 9.2 | 9.1 | 9.0 | 8.4 | 8.3 | 8.2 | 8.1 | 8.0 | 7.4 | 7.3 | 7.2

31.3. 行フィルタ #

デフォルトでは、すべてのパブリッシュされたテーブルのすべてのデータが適切なサブスクライバーにレプリケーションされます。 レプリケーションされたデータは、行フィルタを使用して削減できます。 ユーザーは、動作、セキュリティまたはパフォーマンス上の理由で行フィルタの使用を選択できます。 パブリッシュされたテーブルに行フィルタが設定されている場合、行はそのデータが行フィルタ式を満たす場合にのみレプリケーションされます。 これにより、一連のテーブルを部分的にレプリケーションできます。 行フィルタはテーブルごとに定義されます。 データのフィルタ処理が必要なパブリッシュされたテーブルごとに、テーブル名の後にWHERE句を使用します。 WHERE句はカッコで囲む必要があります。 詳細はCREATE PUBLICATIONを参照してください。

31.3.1. 行フィルタルール #

行フィルタは、変更を発行する前に適用されます。 行フィルタがfalseまたはNULLと評価される場合、行はレプリケーションされません。 WHERE句の式は、レプリケーション接続に使用されるロールと同じロール(CREATE SUBSCRIPTIONCONNECTION句で指定されたロール)で評価されます。 TRUNCATEコマンドに対しては、行フィルタは無効です。

31.3.2. 式の制限 #

WHERE句では単純な式のみを使用できます。 ユーザー定義関数、演算子、型、照合、システム列参照、不変でない組み込み関数は使用できません。

パブリケーションがUPDATEまたはDELETE操作をパブリッシュする場合、行フィルタWHERE句には、レプリカアイデンティティの対象となる列のみを含める必要があります(REPLICA IDENTITYを参照)。 パブリケーションがINSERT操作のみをパブリッシュする場合、行フィルタWHERE句は任意の列を使用できます。

31.3.3. UPDATE変換 #

UPDATEが処理されるたびに、行フィルタ式は古い行と新しい行の両方に対して評価されます(つまり、更新前後のデータを使用します)。 両方の評価がtrueの場合、UPDATE変更がレプリケーションされます。 両方の評価がfalseの場合、変更はレプリケーションされません。 古い行と新しい行のいずれか1つのみが行フィルタ式に一致する場合、データの不整合を回避するためにUPDATEINSERTまたはDELETEに変換されます。 サブスクライバーの行は、パブリッシャーの行フィルタ式で定義されている内容を反映する必要があります。

古い行が行フィルタ式を満たしていて(サブスクライバーに送信された)、新しい行が満たさない場合、データの整合性の観点から、古い行はサブスクライバーから削除される必要があります。 したがって、UPDATEDELETEに変換されます。

古い行が行フィルタ式を満たさず(サブスクライバーに送信されなかった)、新しい行がそれを満たす場合は、データの整合性の観点から、新しい行をサブスクライバーに追加する必要があります。 したがって、UPDATEINSERTに変換されます。

表 31.1は、適用された変換を要約します。

表31.1 UPDATE変換要約

古い行新しい行変換
一致せず一致せずレプリケーションしない
一致せず一致INSERT
一致一致せずDELETE
一致一致UPDATE

31.3.4. パーティション化テーブル #

パブリケーションにパーティション化テーブルが含まれている場合、パブリケーションパラメータpublish_via_partition_rootによって使用される行フィルタが決定されます。 publish_via_partition_roottrueの場合、ルートのパーティション化テーブルの行フィルタが使用されます。 それ以外の場合、publish_via_partition_rootfalse(デフォルト)の場合、パーティションの行フィルタがそれぞれ使用されます。

31.3.5. 初期データ同期 #

サブスクリプションで既存のテーブル・データをコピーする必要があり、パブリケーションにWHERE句が含まれている場合、行フィルタ式を満たすデータのみがサブスクライバーにコピーされます。

サブスクリプションに複数のパブリケーションがあり、テーブルが異なるWHERE句でパブリッシュされている場合は、式のanyを満たす行がコピーされます。 詳細は31.3.6を参照してください。

警告

初期データ同期では、既存のテーブルデータをコピーする際にpublishパラメータが考慮されないため、DMLを使用してレプリケーションされない行がコピーされる場合があります。 31.7.1および31.2.2の例を参照してください。

注記

サブスクライバーが15より前のリリースにある場合、既存のデータのコピーでは、パブリケーションで定義されていても行フィルタは使用されません。 これは、古いリリースではテーブルデータ全体しかコピーできないためです。

31.3.6. 複数行フィルタの統合 #

サブスクリプションに複数のパブリケーションがあり、その中で同じテーブルが異なる行フィルタを使用してパブリッシュされている場合(同じパブリッシュ操作の場合)、これらの式はOR結合され、式のいずれかを満たす行がレプリケーションされます。 これは、次の場合、同じテーブルの他のすべての行フィルタが冗長になることを意味します。

  • パブリケーションの1つに行フィルタがない。

  • パブリケーションの1つがFOR ALL TABLESを使用して作成された。 この句では行フィルタを使用できません。

  • パブリケーションの1つがFOR TABLES IN SCHEMAを使用して作成され、テーブルは参照されたスキーマに属している。 この句では、行フィルタは使用できません。

31.3.7. 例 #

次の例で使用するテーブルをいくつか作成します。

test_pub=# CREATE TABLE t1(a int, b int, c text, PRIMARY KEY(a,c));
CREATE TABLE
test_pub=# CREATE TABLE t2(d int, e int, f int, PRIMARY KEY(d));
CREATE TABLE
test_pub=# CREATE TABLE t3(g int, h int, i int, PRIMARY KEY(g));
CREATE TABLE

いくつかのパブリケーションを作成します。 パブリケーションp1には1つのテーブルt1があり、そのテーブルには行フィルタがあります。 パブリケーションp2には2つのテーブルがあります。 テーブルt1には行フィルタがなく、テーブルt2には行フィルタがあります。 パブリケーションp3には2つのテーブルがあり、両方に行フィルタがあります。

test_pub=# CREATE PUBLICATION p1 FOR TABLE t1 WHERE (a > 5 AND c = 'NSW');
CREATE PUBLICATION
test_pub=# CREATE PUBLICATION p2 FOR TABLE t1, t2 WHERE (e = 99);
CREATE PUBLICATION
test_pub=# CREATE PUBLICATION p3 FOR TABLE t2 WHERE (d = 10), t3 WHERE (g = 10);
CREATE PUBLICATION

psqlを使用して、各パブリケーションの行フィルタ式(定義されている場)を表示することができます。

test_pub=# \dRp+
                               Publication p1
  Owner   | All tables | Inserts | Updates | Deletes | Truncates | Via root
----------+------------+---------+---------+---------+-----------+----------
 postgres | f          | t       | t       | t       | t         | f
Tables:
    "public.t1" WHERE ((a > 5) AND (c = 'NSW'::text))

                               Publication p2
  Owner   | All tables | Inserts | Updates | Deletes | Truncates | Via root
----------+------------+---------+---------+---------+-----------+----------
 postgres | f          | t       | t       | t       | t         | f
Tables:
    "public.t1"
    "public.t2" WHERE (e = 99)

                               Publication p3
  Owner   | All tables | Inserts | Updates | Deletes | Truncates | Via root
----------+------------+---------+---------+---------+-----------+----------
 postgres | f          | t       | t       | t       | t         | f
Tables:
    "public.t2" WHERE (d = 10)
    "public.t3" WHERE (g = 10)

psqlを使用して、各テーブルの行フィルタ式(定義されている場合)を表示できます。 テーブルt1は2つのパブリケーションのメンバですが、p1にのみ行フィルタがあります。 テーブルt2は2つのパブリケーションのメンバですが、それぞれに異なる行フィルタがあります。

test_pub=# \d t1
                 Table "public.t1"
 Column |  Type   | Collation | Nullable | Default
--------+---------+-----------+----------+---------
 a      | integer |           | not null |
 b      | integer |           |          |
 c      | text    |           | not null |
Indexes:
    "t1_pkey" PRIMARY KEY, btree (a, c)
Publications:
    "p1" WHERE ((a > 5) AND (c = 'NSW'::text))
    "p2"

test_pub=# \d t2
                 Table "public.t2"
 Column |  Type   | Collation | Nullable | Default
--------+---------+-----------+----------+---------
 d      | integer |           | not null |
 e      | integer |           |          |
 f      | integer |           |          |
Indexes:
    "t2_pkey" PRIMARY KEY, btree (d)
Publications:
    "p2" WHERE (e = 99)
    "p3" WHERE (d = 10)

test_pub=# \d t3
                 Table "public.t3"
 Column |  Type   | Collation | Nullable | Default
--------+---------+-----------+----------+---------
 g      | integer |           | not null |
 h      | integer |           |          |
 i      | integer |           |          |
Indexes:
    "t3_pkey" PRIMARY KEY, btree (g)
Publications:
    "p3" WHERE (g = 10)

サブスクライバーノードで、パブリッシャーと同じ定義のテーブルt1を作成し、パブリケーションp1をサブスクライブするサブスクリプションs1も作成します。

test_sub=# CREATE TABLE t1(a int, b int, c text, PRIMARY KEY(a,c));
CREATE TABLE
test_sub=# CREATE SUBSCRIPTION s1
test_sub-# CONNECTION 'host=localhost dbname=test_pub application_name=s1'
test_sub-# PUBLICATION p1;
CREATE SUBSCRIPTION

いくつかの行を挿入します。 パブリケーションp1t1 WHERE句を満たす行のみがレプリケーションされます。

test_pub=# INSERT INTO t1 VALUES (2, 102, 'NSW');
INSERT 0 1
test_pub=# INSERT INTO t1 VALUES (3, 103, 'QLD');
INSERT 0 1
test_pub=# INSERT INTO t1 VALUES (4, 104, 'VIC');
INSERT 0 1
test_pub=# INSERT INTO t1 VALUES (5, 105, 'ACT');
INSERT 0 1
test_pub=# INSERT INTO t1 VALUES (6, 106, 'NSW');
INSERT 0 1
test_pub=# INSERT INTO t1 VALUES (7, 107, 'NT');
INSERT 0 1
test_pub=# INSERT INTO t1 VALUES (8, 108, 'QLD');
INSERT 0 1
test_pub=# INSERT INTO t1 VALUES (9, 109, 'NSW');
INSERT 0 1

test_pub=# SELECT * FROM t1;
 a |  b  |  c
---+-----+-----
 2 | 102 | NSW
 3 | 103 | QLD
 4 | 104 | VIC
 5 | 105 | ACT
 6 | 106 | NSW
 7 | 107 | NT
 8 | 108 | QLD
 9 | 109 | NSW
(8 rows)

test_sub=# SELECT * FROM t1;
 a |  b  |  c
---+-----+-----
 6 | 106 | NSW
 9 | 109 | NSW
(2 rows)

古い行の値と新しい行の値の両方がパブリケーションp1t1 WHERE句を満たすデータを更新します。 UPDATEは、通常のように変更をレプリケーションします。

test_pub=# UPDATE t1 SET b = 999 WHERE a = 6;
UPDATE 1

test_pub=# SELECT * FROM t1;
 a |  b  |  c
---+-----+-----
 2 | 102 | NSW
 3 | 103 | QLD
 4 | 104 | VIC
 5 | 105 | ACT
 7 | 107 | NT
 8 | 108 | QLD
 9 | 109 | NSW
 6 | 999 | NSW
(8 rows)

test_sub=# SELECT * FROM t1;
 a |  b  |  c
---+-----+-----
 9 | 109 | NSW
 6 | 999 | NSW
(2 rows)

古い行の値はパブリケーションp1t1 WHERE句を満たしていませんが、新しい行の値はこの句を満たしているデータを更新します。 UPDATEINSERTに変換され、変更がレプリケーションされます。 サブスクライバーの新しい行を参照してください。

test_pub=# UPDATE t1 SET a = 555 WHERE a = 2;
UPDATE 1

test_pub=# SELECT * FROM t1;
  a  |  b  |  c
-----+-----+-----
   3 | 103 | QLD
   4 | 104 | VIC
   5 | 105 | ACT
   7 | 107 | NT
   8 | 108 | QLD
   9 | 109 | NSW
   6 | 999 | NSW
 555 | 102 | NSW
(8 rows)

test_sub=# SELECT * FROM t1;
  a  |  b  |  c
-----+-----+-----
   9 | 109 | NSW
   6 | 999 | NSW
 555 | 102 | NSW
(3 rows)

古い行の値がパブリケーションp1t1 WHERE句を満たしていますが、新しい行の値がこの句を満たしていないデータを更新します。 UPDATEDELETEに変換され、変更がレプリケーションされます。 行がサブスクライバーから削除されていることを確認します。

test_pub=# UPDATE t1 SET c = 'VIC' WHERE a = 9;
UPDATE 1

test_pub=# SELECT * FROM t1;
  a  |  b  |  c
-----+-----+-----
   3 | 103 | QLD
   4 | 104 | VIC
   5 | 105 | ACT
   7 | 107 | NT
   8 | 108 | QLD
   6 | 999 | NSW
 555 | 102 | NSW
   9 | 109 | VIC
(8 rows)

test_sub=# SELECT * FROM t1;
  a  |  b  |  c
-----+-----+-----
   6 | 999 | NSW
 555 | 102 | NSW
(2 rows)

次の例は、パブリケーションパラメータpublish_via_partition_rootによって、親テーブルまたは子テーブルの行フィルタがパーティション化されたテーブルで使用されるかどうかがどのように決定されるかを示しています。

パブリッシャーでパーティション化テーブルを作成します。

test_pub=# CREATE TABLE parent(a int PRIMARY KEY) PARTITION BY RANGE(a);
CREATE TABLE
test_pub=# CREATE TABLE child PARTITION OF parent DEFAULT;
CREATE TABLE

サブスクライバー上に同じテーブルを作成します。

test_sub=# CREATE TABLE parent(a int PRIMARY KEY) PARTITION BY RANGE(a);
CREATE TABLE
test_sub=# CREATE TABLE child PARTITION OF parent DEFAULT;
CREATE TABLE

パブリケーションp4を作成し、サブスクライブします。 パブリケーションパラメータpublish_via_partition_rootはtrueに設定されています。 行フィルタは、パーティション化テーブル(parent)とパーティション(child)の両方に定義されています。

test_pub=# CREATE PUBLICATION p4 FOR TABLE parent WHERE (a < 5), child WHERE (a >= 5)
test_pub-# WITH (publish_via_partition_root=true);
CREATE PUBLICATION

test_sub=# CREATE SUBSCRIPTION s4
test_sub-# CONNECTION 'host=localhost dbname=test_pub application_name=s4'
test_sub-# PUBLICATION p4;
CREATE SUBSCRIPTION

一部の値をおよびテーブルに直接挿入します。 これらの値は、の行フィルタを使用してレプリケーションされます(publish_via_partition_rootがtrueであるため)。

test_pub=# INSERT INTO parent VALUES (2), (4), (6);
INSERT 0 3
test_pub=# INSERT INTO child VALUES (3), (5), (7);
INSERT 0 3

test_pub=# SELECT * FROM parent ORDER BY a;
 a
---
 2
 3
 4
 5
 6
 7
(6 rows)

test_sub=# SELECT * FROM parent ORDER BY a;
 a
---
 2
 3
 4
(3 rows)

同じテストを、異なる値publish_via_partition_rootで繰り返します。 パブリケーションパラメータpublish_via_partition_rootは偽に設定されています。 行フィルタがパーティション(child)に定義されています。

test_pub=# DROP PUBLICATION p4;
DROP PUBLICATION
test_pub=# CREATE PUBLICATION p4 FOR TABLE parent, child WHERE (a >= 5)
test_pub-# WITH (publish_via_partition_root=false);
CREATE PUBLICATION

test_sub=# ALTER SUBSCRIPTION s4 REFRESH PUBLICATION;
ALTER SUBSCRIPTION

パブリッシャーで挿入を前と同じように実行します。 これらはchildの行フィルタを使用してレプリケーションされます(publish_via_partition_rootがfalseであるため)。

test_pub=# TRUNCATE parent;
TRUNCATE TABLE
test_pub=# INSERT INTO parent VALUES (2), (4), (6);
INSERT 0 3
test_pub=# INSERT INTO child VALUES (3), (5), (7);
INSERT 0 3

test_pub=# SELECT * FROM parent ORDER BY a;
 a
---
 2
 3
 4
 5
 6
 7
(6 rows)

test_sub=# SELECT * FROM child ORDER BY a;
 a
---
 5
 6
 7
(3 rows)