Postgresql 中文操作指南

31.2. Subscription #

subscription 是逻辑复制的下游部分。定义订阅的节点称为 subscriber。订阅定义了与另一个数据库的连接以及它想要订阅的一组出版物(一个或多个)。

订阅数据库的行为与任何其他 PostgreSQL 实例相同,并且可以通过自己定义出版物,用作其他数据库的发布者。

如果需要,订阅节点可以有多个订阅。可以在单个发布者-订阅者对之间定义多个订阅,在这种情况下,必须注意确保订阅的出版物对象不会重叠。

每个订阅都将通过一个复制槽接收更改(请参阅 Section 27.2.6)。对于现有表数据的初始数据同步,可能需要额外的复制槽,并且这些槽将在数据同步结束时被删除。

逻辑复制订阅可以成为同步复制的备用复制(请参阅 Section 27.2.8)。默认情况下,备用名称是订阅名称。可以将备用名称指定为 application_name 订阅连接信息中。

如果当前用户是超级用户,pg_dump 会转储订阅。否则,会编写一条警告并跳过订阅,因为非超级用户无法从 pg_subscription 目录中读取所有订阅信息。

使用 CREATE SUBSCRIPTION 添加订阅,可以使用 ALTER SUBSCRIPTION 命令随时停止/恢复订阅,并可以使用 DROP SUBSCRIPTION 命令删除订阅。

当一个订阅被删除并重新创建,同步信息将丢失。这意味着数据需要在之后重新同步。

模式定义不会被复制,并且已发布的表必须位于订户中。只有常规表可能是复制的目标。例如,您无法复制到视图。

表之间在发布者和订户之间通过完全限定的表名进行匹配。不支持针对订户中名称不同的表复制。

表中的列也按名称匹配。订阅者表中的列顺序不必与发布者表中列的顺序相匹配。只要数据文本表示形式可转换为目标类型,那么列的数据类型不必匹配。例如,可以从 integer 类型列复制到 bigint 类型列。目标表还可以包含已发布表未提供的其他列。任何此类列都将填充目标表定义中指定的默认值。但是,二进制格式的逻辑复制更加严格。有关详细信息,请参阅 CREATE SUBSCRIPTIONbinary 选项。

31.2.1. Replication Slot Management #

如前所述,每个(活动)订阅从远程(发布)端的复制槽中接收更改。

附加表同步槽通常是临时的,在内部创建以执行初始表同步,并在不再需要它们时自动删除。这些表同步槽生成了名称:“pg%u_sync_%u_%llu_”(参数:订阅 oid,表 relid,系统标识符 sysid

通常,在使用 CREATE SUBSCRIPTION 创建订阅时,远程复制槽会自动创建,并且在使用 DROP SUBSCRIPTION 删除订阅时,它会自动删除。然而,在某些情况下,单独操作订阅和底层复制槽会很有用或有必要。下面是一些场景:

31.2.2. Examples: Set Up Logical Replication #

在发布者上创建一些测试表。

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

在订户上创建相同的表。

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

将数据插入到发布者端的表中。

test_pub=# INSERT INTO t1 VALUES (1, 'one'), (2, 'two'), (3, 'three');
INSERT 0 3
test_pub=# INSERT INTO t2 VALUES (1, 'A'), (2, 'B'), (3, 'C');
INSERT 0 3
test_pub=# INSERT INTO t3 VALUES (1, 'i'), (2, 'ii'), (3, 'iii');
INSERT 0 3

为表创建发布。 pub2pub3a 发布不允许一些 publish 操作。 pub3b 发布具有行筛选器(请参阅 Section 31.3 )。

test_pub=# CREATE PUBLICATION pub1 FOR TABLE t1;
CREATE PUBLICATION
test_pub=# CREATE PUBLICATION pub2 FOR TABLE t2 WITH (publish = 'truncate');
CREATE PUBLICATION
test_pub=# CREATE PUBLICATION pub3a FOR TABLE t3 WITH (publish = 'truncate');
CREATE PUBLICATION
test_pub=# CREATE PUBLICATION pub3b FOR TABLE t3 WHERE (e > 5);
CREATE PUBLICATION

为发布创建订阅。订阅 sub3 订阅 pub3apub3b。默认情况下,所有订阅都会复制初始数据。

test_sub=# CREATE SUBSCRIPTION sub1
test_sub-# CONNECTION 'host=localhost dbname=test_pub application_name=sub1'
test_sub-# PUBLICATION pub1;
CREATE SUBSCRIPTION
test_sub=# CREATE SUBSCRIPTION sub2
test_sub-# CONNECTION 'host=localhost dbname=test_pub application_name=sub2'
test_sub-# PUBLICATION pub2;
CREATE SUBSCRIPTION
test_sub=# CREATE SUBSCRIPTION sub3
test_sub-# CONNECTION 'host=localhost dbname=test_pub application_name=sub3'
test_sub-# PUBLICATION pub3a, pub3b;
CREATE SUBSCRIPTION

请注意,初始表数据会被复制,无论发布的 publish 操作是什么。

test_sub=# SELECT * FROM t1;
 a |   b
---+-------
 1 | one
 2 | two
 3 | three
(3 rows)

test_sub=# SELECT * FROM t2;
 c | d
---+---
 1 | A
 2 | B
 3 | C
(3 rows)

此外,由于初始数据复制忽略 publish 操作,并且由于发布 pub3a 没有行过滤器,这意味着复制的表 t3 包含所有行,即使它们与发布 pub3b 的行过滤器不匹配。

test_sub=# SELECT * FROM t3;
 e |  f
---+-----
 1 | i
 2 | ii
 3 | iii
(3 rows)

将更多数据插入到发布者端的表中。

test_pub=# INSERT INTO t1 VALUES (4, 'four'), (5, 'five'), (6, 'six');
INSERT 0 3
test_pub=# INSERT INTO t2 VALUES (4, 'D'), (5, 'E'), (6, 'F');
INSERT 0 3
test_pub=# INSERT INTO t3 VALUES (4, 'iv'), (5, 'v'), (6, 'vi');
INSERT 0 3

现在,发布者端数据看起来像这样:

test_pub=# SELECT * FROM t1;
 a |   b
---+-------
 1 | one
 2 | two
 3 | three
 4 | four
 5 | five
 6 | six
(6 rows)

test_pub=# SELECT * FROM t2;
 c | d
---+---
 1 | A
 2 | B
 3 | C
 4 | D
 5 | E
 6 | F
(6 rows)

test_pub=# SELECT * FROM t3;
 e |  f
---+-----
 1 | i
 2 | ii
 3 | iii
 4 | iv
 5 | v
 6 | vi
(6 rows)

请注意,在正常复制期间,使用了适当的 publish 操作。这意味着发布 pub2pub3a 不会复制 INSERT。此外,发布 pub3b 仅复制与 pub3b 的行过滤器匹配的数据。现在,订户端数据看起来像这样:

test_sub=# SELECT * FROM t1;
 a |   b
---+-------
 1 | one
 2 | two
 3 | three
 4 | four
 5 | five
 6 | six
(6 rows)

test_sub=# SELECT * FROM t2;
 c | d
---+---
 1 | A
 2 | B
 3 | C
(3 rows)

test_sub=# SELECT * FROM t3;
 e |  f
---+-----
 1 | i
 2 | ii
 3 | iii
 6 | vi
(4 rows)

31.2.3. Examples: Deferred Replication Slot Creation #

在某些情况下(例如 Section 31.2.1),如果未自动创建远程复制槽,则用户必须在激活订阅之前手动创建它。创建槽和激活订阅的步骤显示在以下示例中。这些示例指定了标准逻辑解码输出插件(pgoutput),这是内置逻辑复制所使用的插件。

首先,为要使用的示例创建一个发布。

test_pub=# CREATE PUBLICATION pub1 FOR ALL TABLES;
CREATE PUBLICATION

示例 1:其中订阅显示 connect = false

示例 2:其中订阅表示 connect = false ,但也指定了 slot_name 选项。

示例 3:其中订阅指定了 slot_name = NONE