PostgreSQL逻辑复制是基于预写日志(WAL)解析的同步机制,允许将特定表的数据变更发送到订阅端。在实际业务中,往往只需要同步部分表或者表中的部分行,如果直接发布整个数据库,会带来不必要的网络带宽消耗和订阅端写入压力。通过合理的过滤策略,可以把同步范围精确控制在最小集合内。

一、表级过滤:使用发布白名单
逻辑复制的过滤最先发生在发布(Publication)定义阶段。创建发布时,可以通过显式指定表名来构成白名单,只有被列入的表才会被加入变更捕获范围。这种方式在源头减少了WAL解析量,是最基础也最常用的过滤手段。
下面的示例创建了一个只发布 users 和 orders 两张表的发布,并且只发送 INSERT 与 UPDATE 操作:
-- 创建发布,仅包含两张表,且只同步部分操作 CREATE PUBLICATION my_pub FOR TABLE users, orders WITH (publish = 'insert, update'); -- 查看发布包含的表 SELECT pubname, schemaname, tablename FROM pg_publication_tables WHERE pubname = 'my_pub';
需要注意的是,被发布的表必须具备主键或合理的 REPLICA IDENTITY,否则 UPDATE 和 DELETE 在订阅端无法定位行。如果后期需要新增表,可以使用 ALTER PUBLICATION 追加,但要记得在订阅端同时创建对应的表结构与订阅刷新。
表级过滤的优点是配置简单、对性能影响小,缺点是粒度较粗。如果业务只需要订单表中某个客户的数据,仍会传输整张表的变更。此时就需要更细的行级过滤。
二、行级过滤的实现思路
PostgreSQL原生发布语法并不直接支持 WHERE 条件过滤行,但可以通过组合手段达成类似效果。常见做法是在发布端使用分区表,只把目标分区加入发布;或者通过规则与触发器将需要同步的行列复制到一张影子表,再发布影子表。
另一种更灵活的方式是借助逻辑解码插件(如 pgoutput 配合自定义客户端)在订阅端丢弃无关行,但这会增加订阅应用复杂度。下面演示用触发器维护影子表实现行级过滤:
-- 影子表,仅保存需要同步的高价值订单
CREATE TABLE orders_filtered (LIKE orders INCLUDING ALL);
-- 触发器函数,只复制金额大于1000的订单
CREATE OR REPLACE FUNCTION fn_filter_orders()
RETURNS TRIGGER AS $$
BEGIN
IF NEW.amount > 1000 THEN
INSERT INTO orders_filtered VALUES (NEW.*);
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- 在原表上挂载触发器
CREATE TRIGGER trg_filter_orders
AFTER INSERT OR UPDATE ON orders
FOR EACH ROW EXECUTE FUNCTION fn_filter_orders();
-- 仅发布影子表
CREATE PUBLICATION filtered_pub FOR TABLE orders_filtered;
这种方案把过滤逻辑放在写入路径上,对业务表侵入较小,且发布端WAL量明显下降。但触发器会带来额外写开销,高并发场景需评估性能。同时,DELETE操作不会自动同步到影子表,需要补充对应的删除触发器。
从一致性角度看,行级过滤若在订阅端做,可能出现发布端已删、订阅端先收到后过滤而漏删的问题。因此关键数据建议优先在发布端裁剪,或保证过滤条件幂等。
三、REPLICA IDENTITY对过滤的影响
当使用行级更新或删除时,订阅端必须能根据旧值找到对应行。PostgreSQL通过 REPLICA IDENTITY 控制WAL中记录哪些列作为身份标识。默认使用主键,若设为 FULL 则记录所有列,会增加日志体积;设为 NOTHING 则不支持键更新。
修改表的身份标识示例如下:
-- 使用唯一索引作为身份标识 ALTER TABLE orders REPLICA IDENTITY USING INDEX ui_orders_no; -- 查看当前设置 SELECT relname, relreplident FROM pg_class WHERE relname = 'orders';
如果过滤策略依赖非主键列,而该列未包含在 REPLICA IDENTITY 中,订阅端就无法正确应用变更。因此在设计行级过滤前,应先确认身份标识覆盖过滤与定位所需的列。
综合来看,表级过滤负责宏观瘦身,行级过滤解决业务精筛,REPLICA IDENTITY 则是二者正确运行的底层保障。在生产中建议先定表清单,再按数据特征选择影子表或分区方案,最后校验身份标识与订阅刷新流程。
四、过滤策略对比与选型
我们将三种常见方式做个简单对比:
| 策略 | 实现位置 | 性能开销 | 适用场景 |
|---|---|---|---|
| 发布白名单 | 发布端 | 低 | 只需同步部分表 |
| 影子表加触发器 | 发布端 | 中 | 按条件筛选行且写并发可控 |
| 订阅端丢弃 | 订阅端 | 高 | 过滤逻辑频繁变化、暂不能改表结构 |
从运维角度,发布端过滤最易于排查问题,因为发布定义可通过系统表直接查询。订阅端过滤则常与具体解码程序绑定,变更需发版。若团队更关注稳定性,应优先采用前两种组合。
最后提醒,任何过滤调整都应先在测试环境验证数据一致性,并利用 pg_recvlogical 或订阅端计数核对行数差异,防止静默漏同步。
PostgreSQLlogical_replicationreplication_filter修改时间:2026-08-11 22:06:30