在這篇博文中,我將簡要介紹 PostgreSQL 15發布行過濾器的新特性。此功能是由富士通 OSS 團隊與 PostgreSQL 開源社區的其他成員密切合作添加的。
用戶可能選擇定義邏輯復制行過濾器的原因有多種,例如減少網絡流量、減少噪音或消除不良數據、僅復制與訂閱者相關的數據以及隱藏敏感信息。
目錄導讀
引言
通常,當使用邏輯復制 PUB/SUB 時,發布表的所有數據更改都將復制到相應的訂閱者。用戶可以使用新的行過濾器功能限制復制,以便只有與過濾器表達式匹配的行數據被復制。
功能概述
在 CREATE PUBLICATION 時,可選擇為每個表指定行過濾器。為每個要進行行過濾的表添加行過濾器 WHERE 子句。每個發布可能有零個或多個行過濾器。
修改 CREATE PUBLICATION 語法
這是一個簡化的 CREATE PUBLICATION 語法,突出顯示為 PostgreSQL 15 添加的新行過濾器 WHERE 子句:
CREATE PUBLICATION <pub-name> FOR TABLE <table-list>
<table-list> ::= <table-list-item> [, <table-list>]
<table-list-item> ::= <table-name> [ WHERE (<row-filter-expression>) ]
行過濾器表達式
行過濾器 WHERE 子句只允許簡單的表達式,包括基本函數和邏輯運算符。它只能引用它所屬的表的列。如果發布發布了任何 UPDATE 或 DELETE 操作,行過濾器表達式則必須僅包含表的“副本標識”所涵蓋的列。如果發布僅發布 INSERT 操作,則行過濾器表達式可以使用任何列。
示例1
CREATE PUBLICATION cheap_widgets
FOR TABLE widget WHERE (price < 1.99);
示例2
CREATE PUBLICATION sales_people
FOR TABLE employees WHERE (role <> 'manager' AND dept = 'sales');
示例3
CREATE PUBLICATION rate_usa FOR TABLE exchange_rates WHERE (country = 'us');
CREATE PUBLICATION rate_uk FOR TABLE exchange_rates WHERE (country = 'uk');
CREATE PUBLICATION rate_france FOR TABLE exchange_rates WHERE (country = 'fr');
應用行過濾器
在決定發布更改之前應用行過濾器。如果行過濾器表達式的計算結果為 NULL 或 false,則不會復制該行。
-
TRUNCATE TABLE 命令忽略行過濾器。
-
過濾的 INSERT 被復制為 INSERT。
-
過濾的 DELETE 被復制為 DELETE。
過濾的 UPDATE 更復雜,因為目標是訂閱方復制的表數據必須最終遵守發布者上定義的行過濾器表達式。要決定實現這一點所需的操作意味著,無論何時處理 UPDATE,都必須針對舊行數據和新行數據(即 UPDATE 之前和之后)評估行過濾器表達式。
-
如果舊行不滿足行過濾器表達式(我們斷言該行在訂閱服務器上不存在),但新行滿足,那么為了數據一致性,應該將新行添加到訂閱服務器——UPDATE 轉換為插入。
-
如果舊行滿足行過濾器表達式(我們斷言該行已經發送給訂閱者),但新行不滿足,那么為了數據一致性,應該從訂閱者中刪除舊行 - UPDATE 轉換為刪除。
UPDATE 轉變
| 舊行 | 新行 | 復制方法 |
|---|---|---|
| - | - | 不要復制任何東西 |
| - | 匹配過濾器 | 在訂閱者上插入新行 |
| 匹配過濾器 | - | 刪除訂閱者上的舊行 |
| 匹配過濾器 | 匹配過濾器 | 在訂閱者上復制 UPDATE |
組合多個行過濾器
有時訂閱可能會訂閱多個發布,其中同一個表是使用不同的行過濾器 WHERE 子句發布的。如果發生這種情況,那么這些表達式將被OR-ed在一起,以便復制滿足任何表達式的行。
這也意味著如果表的訂閱發布之一沒有行過濾器,則該表的所有其他行過濾器將被忽略。

初始表同步
當用戶選擇使用(默認)copy_data = true訂閱參數時,將僅復制滿足發布的行過濾器的預先存在的數據。
psql 命令的增強
作為這一新功能的一部分,PostgreSQL 15 psql 命令也進行了修改,以提供有關行過濾器表達式的有用信息。
顯示表命令 ( \d ) 現在在表所屬的任何發布上顯示 WHERE 子句。顯示發布命令 ( \dRp+ ) 現在顯示任何表的 WHERE 子句。
例子:
postgres=# CREATE TABLE data(id int, rgb text);
CREATE TABLE
postgres=# CREATE PUBLICATION pub_data_all FOR TABLE data;
CREATE PUBLICATION
postgres=# CREATE PUBLICATION pub_data_blue FOR TABLE data WHERE (rgb = 'B');
CREATE PUBLICATION
postgres=# CREATE PUBLICATION pub_data_red FOR TABLE data WHERE (rgb = 'R');
CREATE PUBLICATION
postgres=# \d data
Table "public.data"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
id | integer | | |
rgb | text | | |
Publications:
"pub_data_all"
"pub_data_blue" WHERE (rgb = 'B'::text)
"pub_data_red" WHERE (rgb = 'R'::text)
postgres=# \dRp+
Publication pub_data_all
Owner | All tables | Inserts | Updates | Deletes | Truncates | Via root
----------+------------+---------+---------+---------+-----------+----------
postgres | f | t | t | t | t | f
Tables:
"public.data"
Publication pub_data_blue
Owner | All tables | Inserts | Updates | Deletes | Truncates | Via root
----------+------------+---------+---------+---------+-----------+----------
postgres | f | t | t | t | t | f
Tables:
"public.data" WHERE (rgb = 'B'::text)
Publication pub_data_red
Owner | All tables | Inserts | Updates | Deletes | Truncates | Via root
----------+------------+---------+---------+---------+-----------+----------
postgres | f | t | t | t | t | f
Tables:
"public.data" WHERE (rgb = 'R'::text)
postgres=#
影響
用戶可能選擇定義邏輯復制行過濾器的原因有多種:
- 通過僅復制大型數據表的一小部分來減少網絡流量(提高性能)。
例子:
CREATE PUBLICATION pub_data_2205
FOR TABLE bank_transactions WHERE (year = 2022 AND month = 'May') ;
- 減少噪音或消除不良數據。
例子:
CREATE PUBLICATION pub_data_good
FOR TABLE sensor WHERE (value IS NOT NULL AND value > 0) ;
- 僅提供與訂閱者節點相關的數據。
例子:
CREATE PUBLICATION pub_data_new_york
FOR TABLE weather WHERE (state = 'NY') ;
- 通過隱藏(而不是復制)敏感信息來充當一種安全形式。
例子:
CREATE PUBLICATION pub_data_salary
FOR TABLE 員工WHERE (role <> 'manager') ;
后記
添加行過濾是 PostgreSQL 15 邏輯復制的主要功能。此功能為用戶的工具箱提供了另一種工具,允許他們創建更復雜或定制的邏輯復制解決方案。富士通 OSS 團隊將繼續幫助增強和添加更多功能到 PostgreSQL 邏輯復制。
PostgreSQL 15 中也添加了與行過濾器相關的功能,即邏輯復制列列表。這將是我的一位同事即將發表的博客的主題。
原文地址:Introducing publication row filters
原文作者:Peter Smith




