デフォルトでは、すべてのパブリッシュされたテーブルのすべてのデータが適切なサブスクライバーにレプリケーションされます。
レプリケーションされたデータは、行フィルタを使用して削減できます。
ユーザーは、動作、セキュリティまたはパフォーマンス上の理由で行フィルタの使用を選択できます。
パブリッシュされたテーブルに行フィルタが設定されている場合、行はそのデータが行フィルタ式を満たす場合にのみレプリケーションされます。
これにより、一連のテーブルを部分的にレプリケーションできます。
行フィルタはテーブルごとに定義されます。
データのフィルタ処理が必要なパブリッシュされたテーブルごとに、テーブル名の後にWHERE
句を使用します。
WHERE
句はカッコで囲む必要があります。
詳細はCREATE PUBLICATIONを参照してください。
行フィルタは、変更を発行する前に適用されます。
行フィルタがfalse
またはNULL
と評価される場合、行はレプリケーションされません。
WHERE
句の式は、レプリケーション接続に使用されるロールと同じロール(CREATE SUBSCRIPTIONのCONNECTION
句で指定されたロール)で評価されます。
TRUNCATE
コマンドに対しては、行フィルタは無効です。
WHERE
句では単純な式のみを使用できます。
ユーザー定義関数、演算子、型、照合、システム列参照、不変でない組み込み関数は使用できません。
パブリケーションがUPDATE
またはDELETE
操作をパブリッシュする場合、行フィルタWHERE
句には、レプリカアイデンティティの対象となる列のみを含める必要があります(REPLICA IDENTITY
を参照)。
パブリケーションがINSERT
操作のみをパブリッシュする場合、行フィルタWHERE
句は任意の列を使用できます。
UPDATE
が処理されるたびに、行フィルタ式は古い行と新しい行の両方に対して評価されます(つまり、更新前後のデータを使用します)。
両方の評価がtrue
の場合、UPDATE
変更がレプリケーションされます。
両方の評価がfalse
の場合、変更はレプリケーションされません。
古い行と新しい行のいずれか1つのみが行フィルタ式に一致する場合、データの不整合を回避するためにUPDATE
がINSERT
またはDELETE
に変換されます。
サブスクライバーの行は、パブリッシャーの行フィルタ式で定義されている内容を反映する必要があります。
古い行が行フィルタ式を満たしていて(サブスクライバーに送信された)、新しい行が満たさない場合、データの整合性の観点から、古い行はサブスクライバーから削除される必要があります。
したがって、UPDATE
はDELETE
に変換されます。
古い行が行フィルタ式を満たさず(サブスクライバーに送信されなかった)、新しい行がそれを満たす場合は、データの整合性の観点から、新しい行をサブスクライバーに追加する必要があります。
したがって、UPDATE
はINSERT
に変換されます。
表 31.1は、適用された変換を要約します。
表31.1 UPDATE
変換要約
古い行 | 新しい行 | 変換 |
---|---|---|
一致せず | 一致せず | レプリケーションしない |
一致せず | 一致 | INSERT |
一致 | 一致せず | DELETE |
一致 | 一致 | UPDATE |
パブリケーションにパーティション化テーブルが含まれている場合、パブリケーションパラメータpublish_via_partition_root
によって使用される行フィルタが決定されます。
publish_via_partition_root
がtrue
の場合、ルートのパーティション化テーブルの行フィルタが使用されます。
それ以外の場合、publish_via_partition_root
がfalse
(デフォルト)の場合、パーティションの行フィルタがそれぞれ使用されます。
サブスクリプションで既存のテーブル・データをコピーする必要があり、パブリケーションにWHERE
句が含まれている場合、行フィルタ式を満たすデータのみがサブスクライバーにコピーされます。
サブスクリプションに複数のパブリケーションがあり、テーブルが異なるWHERE
句でパブリッシュされている場合は、式のanyを満たす行がコピーされます。
詳細は31.3.6を参照してください。
初期データ同期では、既存のテーブルデータをコピーする際にpublish
パラメータが考慮されないため、DMLを使用してレプリケーションされない行がコピーされる場合があります。
31.7.1および31.2.2の例を参照してください。
サブスクライバーが15より前のリリースにある場合、既存のデータのコピーでは、パブリケーションで定義されていても行フィルタは使用されません。 これは、古いリリースではテーブルデータ全体しかコピーできないためです。
サブスクリプションに複数のパブリケーションがあり、その中で同じテーブルが異なる行フィルタを使用してパブリッシュされている場合(同じパブリッシュ
操作の場合)、これらの式はOR結合され、式のいずれかを満たす行がレプリケーションされます。
これは、次の場合、同じテーブルの他のすべての行フィルタが冗長になることを意味します。
パブリケーションの1つに行フィルタがない。
パブリケーションの1つがFOR ALL TABLES
を使用して作成された。
この句では行フィルタを使用できません。
パブリケーションの1つがFOR TABLES IN SCHEMA
を使用して作成され、テーブルは参照されたスキーマに属している。
この句では、行フィルタは使用できません。
次の例で使用するテーブルをいくつか作成します。
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
いくつかの行を挿入します。
パブリケーションp1
のt1 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)
古い行の値と新しい行の値の両方がパブリケーションp1
のt1 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)
古い行の値はパブリケーションp1
のt1 WHERE
句を満たしていませんが、新しい行の値はこの句を満たしているデータを更新します。
UPDATE
はINSERT
に変換され、変更がレプリケーションされます。
サブスクライバーの新しい行を参照してください。
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)
古い行の値がパブリケーションp1
のt1 WHERE
句を満たしていますが、新しい行の値がこの句を満たしていないデータを更新します。
UPDATE
はDELETE
に変換され、変更がレプリケーションされます。
行がサブスクライバーから削除されていることを確認します。
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)