預設情況下,所有已發布表格的所有資料都會複寫到適當的訂閱者。複寫的資料可以使用列篩選器來減少。使用者可能會因為行為、安全性或效能原因而選擇使用列篩選器。如果已發布的表格設定了列篩選器,則只有當其資料滿足列篩選器運算式時,才會複寫列。這允許部分複寫一組表格。列篩選器是針對每個表格定義的。在表格名稱之後使用 WHERE
子句,針對每個需要篩選掉資料的已發布表格。WHERE
子句必須用括號括起來。有關詳細資訊,請參閱CREATE PUBLICATION。
列篩選器會在發布變更之前套用。如果列篩選器的評估結果為 false
或 NULL
,則不會複寫該列。WHERE
子句運算式會使用與複寫連線相同的角色進行評估 (即,CREATE SUBSCRIPTION 的 CONNECTION
子句中指定的角色)。列篩選器對 TRUNCATE
命令沒有作用。
WHERE
子句僅允許簡單運算式。它不能包含使用者定義的函式、運算子、類型和定序、系統欄位參考或非不可變的內建函式。
如果發布項目發布 UPDATE
或 DELETE
操作,則列篩選器 WHERE
子句必須僅包含 replica identity 所涵蓋的欄位 (請參閱 REPLICA IDENTITY
)。如果發布項目僅發布 INSERT
操作,則列篩選器 WHERE
子句可以使用任何欄位。
每當處理 UPDATE
時,都會針對舊列和新列評估列篩選器運算式 (即,使用更新前後的資料)。如果兩個評估結果都為 true
,則會複寫 UPDATE
變更。如果兩個評估結果都為 false
,則不會複寫變更。如果只有一個舊/新列符合列篩選器運算式,則 UPDATE
會轉換為 INSERT
或 DELETE
,以避免任何資料不一致。訂閱者上的列應反映發布者上列篩選器運算式定義的內容。
如果舊列滿足列篩選器運算式 (已傳送到訂閱者),但新列不滿足,那麼從資料一致性的角度來看,應該從訂閱者中移除舊列。因此,UPDATE
會轉換為 DELETE
。
如果舊列不滿足列篩選器運算式 (未傳送到訂閱者),但新列滿足,那麼從資料一致性的角度來看,應該將新列新增到訂閱者。因此,UPDATE
會轉換為 INSERT
。
表 29.1 總結了套用的轉換。
表 29.1. UPDATE
轉換摘要
舊列 | 新列 | 轉換 |
---|---|---|
不符合 | 不符合 | 不複寫 |
不符合 | 符合 | INSERT |
符合 | 不符合 | DELETE |
符合 | 符合 | UPDATE |
如果發布項目包含分割表,則發布項目參數 publish_via_partition_root
決定使用哪個列篩選器。如果 publish_via_partition_root
為 true
,則使用根分割表的列篩選器。否則,如果 publish_via_partition_root
為 false
(預設值),則使用每個分割區的列篩選器。
如果訂閱需要複製先前存在的表格資料,並且發布項目包含 WHERE
子句,則只會將滿足列篩選器運算式的資料複製到訂閱者。
如果訂閱中有多個發布項目,其中一個表格已使用不同的 WHERE
子句發布,則會複製滿足任何運算式的列。有關詳細資訊,請參閱第 29.4.6 節。
由於初始資料同步在複製現有表格資料時不考慮 publish
參數,因此可能會複製某些不會使用 DML 複寫的列。請參閱第 29.8.1 節,並參閱第 29.2.2 節 以取得範例。
如果訂閱者是 15 之前的版本,即使在發布項目中定義了列篩選器,複製先前存在的資料也不會使用列篩選器。這是因為舊版本只能複製整個表格資料。
如果訂閱包含多個發布,其中相同的資料表已使用不同的列篩選器發布(對於相同的 publish
操作),則這些表達式會進行 OR 運算,以便滿足 任何 表達式的列將被複製。這表示如果符合以下情況,則相同資料表的所有其他列篩選器都會變得多餘:
其中一個發布沒有列篩選器。
其中一個發布是使用 FOR ALL TABLES
建立的。此子句不允許列篩選器。
其中一個發布是使用 FOR TABLES IN SCHEMA
建立的,且資料表屬於所參照的 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
有一個資料表 (t1
),且該資料表具有列篩選器。發布 p2
有兩個資料表。資料表 t1
沒有列篩選器,而資料表 t2
則有列篩選器。發布 p3
有兩個資料表,且它們都具有列篩選器。
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
是兩個發布的成員,但僅在 p1
中具有列篩選器。請注意,資料表 t2
是兩個發布的成員,且每個發布中都有不同的列篩選器。
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
,並建立訂閱 s1
,該訂閱會訂閱發布 p1
。
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
直接將一些值插入 parent
和 child
資料表中。它們使用 parent
的列篩選器進行複製(因為 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
設為 false。在分割區 (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)
如果您在文件中發現任何不正確、與您使用特定功能的經驗不符或需要進一步澄清的地方,請使用此表單來報告文件問題。