CREATE SUBSCRIPTION — 定义一个新的订阅
CREATE SUBSCRIPTIONsubscription_nameCONNECTION 'conninfo' PUBLICATIONpublication_name[, ...] [ WITH (subscription_parameter[=value] [, ... ] ) ]
CREATE SUBSCRIPTION添加一个新的逻辑复制订阅。 创建订阅的用户将成为该订阅的所有者。订阅名称必须与当前数据库中 任何现有订阅的名称不同。
订阅表示与发布者的复制连接。因此,除了在本地系统目录中添加定义之外, 该命令通常还会在发布者上创建一个复制槽。
除非订阅初始即被禁用,否则在执行该命令所在事务提交时,会启动一个 逻辑复制工作进程为新订阅复制数据。
要能够创建订阅,必须具有pg_create_subscription角色的权限, 以及当前数据库上的CREATE权限。
关于订阅以及整个逻辑复制的更多信息,请参见 Section 29.2和 Chapter 29。
subscription_name #新订阅的名称。
CONNECTION 'conninfo' #定义如何连接到发布者数据库的libpq连接字符串。 详情请参见Section 32.1.1。
PUBLICATION publication_name [, ...] #要订阅的发布者上的发布名称。
WITH ( subscription_parameter [= value] [, ... ] ) #该子句为订阅指定可选参数。
下列参数控制订阅创建期间的行为:
connect (boolean) #指定CREATE SUBSCRIPTION命令是否连接到 发布者。默认值为true。将其设为 false会强制把create_slot、 enabled和copy_data的值 设为false。(不能将connect 设为false的同时,再把create_slot、 enabled或copy_data设为 true。)
由于该选项为false时不会建立连接,因此不会订阅任何表。 要启动复制,你必须手工创建复制槽、在需要时启用故障切换、启用订阅, 并刷新订阅。示例见 Section 29.2.3。
create_slot (boolean) #指定该命令是否应在发布者上创建复制槽。默认值为 true。
如果设为false,则必须以其他方式自行创建 发布者上的复制槽。示例见 Section 29.2.3。
enabled (boolean) #指定订阅是应当主动进行复制,还是仅完成设置但暂不启动。 默认值为true。
slot_name (string) #要使用的发布者上的复制槽名称。默认使用订阅名称作为槽名。
将slot_name设为NONE表示该订阅 不关联任何复制槽。这类订阅还必须同时将enabled 和create_slot设为false。 当你打算稍后手工创建复制槽时,可使用此设置。示例见 Section 29.2.3。
将slot_name设为有效名称且 create_slot设为false时, 所指定复制槽的failover属性值可能与订阅中对应的 failover参数不同。应始终确保该槽的 failover属性与订阅中的对应参数一致,反之亦然。 否则,发布者上的该槽的行为可能与这些订阅选项所表明的不同:例如, 即使订阅的failover选项已禁用,发布者上的该槽仍可能 被同步到备库;或者即使订阅的failover选项已启用, 该槽也可能不会被同步到备库。
下列参数控制订阅创建后的复制行为:
binary (boolean) #指定订阅是否请求发布者以二进制格式(而不是文本格式)发送数据。 默认值为false。任何初始表同步复制 (见copy_data)也使用相同格式。二进制格式可能 比文本格式更快,但在不同机器架构和 PostgreSQL版本之间的可移植性较差。 二进制格式对数据类型非常敏感;例如,虽然在文本格式下可以正常工作, 但它不允许从smallint列复制到integer列。 即使启用了此选项,也只有具有二进制发送和接收函数的数据类型才会以 二进制方式传输。注意,初始同步要求所有数据类型都具有二进制发送和 接收函数,否则同步将失败(关于发送/接收函数的更多信息,请参见 CREATE TYPE)。
在进行跨版本复制时,可能会出现这样的情况:发布者对某种数据类型有 二进制发送函数,但订阅者缺少该类型的二进制接收函数。在这种情况下, 数据传输会失败,因此不能使用binary选项。
如果发布者使用的是 16 之前版本的 PostgreSQL,那么即使 binary = true,任何初始表同步也都会使用 文本格式。
copy_data (boolean) #指定复制开始时是否复制所订阅发布中的预先存在的数据。 默认值为true。
如果这些发布包含WHERE子句,将会影响被复制的数据。 详情请参见Notes。
关于copy_data = true如何与 origin参数相互作用的细节,请参见 Notes。
streaming (enum) #指定是否为该订阅启用进行中事务的流式传输。默认值为 parallel,表示如果有可用的并行应用工作进程, 接收到的更改会直接通过其中之一应用。如果没有空闲的并行应用工作进程 可以处理流式事务,那么这些更改会写入临时文件,并在事务提交后再应用。 注意,如果并行应用工作进程中发生错误,远端事务的 finish LSN 可能不会记录到服务器日志中。
当发布者与订阅者的模式不同时,存在发生死锁的风险,尽管这种情况 很少见。应用工作进程会自动重试这些事务。
如果设为on,接收到的更改会写入临时文件,然后仅在 事务在发布者上提交且被订阅者接收之后才应用。
如果设为off,所有事务都会先在发布者上完全解码, 然后才整体发送给订阅者。
synchronous_commit (enum) #该参数的值会覆盖此订阅应用工作进程中的 synchronous_commit设置。默认值为 off。
对逻辑复制来说,使用off是安全的:如果订阅者因 缺少同步而丢失了事务,数据会再次从发布者发送过来。
在进行同步逻辑复制时,可能更适合使用不同的设置。逻辑复制工作进程会向 发布者报告写入和刷盘位置,而在使用同步复制时,发布者会等待真正的刷盘完成。 这意味着,当订阅被用于同步复制时,将订阅者的 synchronous_commit设为off 可能会增加发布者上COMMIT的延迟。在这种场景下, 将synchronous_commit设为local 或更高可能更有利。
two_phase (boolean) #指定是否为该订阅启用两阶段提交。默认值为 false。
启用两阶段提交时,预备事务会在 PREPARE TRANSACTION时发送给订阅者,并且在 订阅者上也会作为两阶段事务处理。否则,预备事务只有在提交时才会 发送给订阅者,随后由订阅者立即处理。
两阶段提交的实现要求复制已经成功完成初始表同步阶段。因此,即使订阅 启用了two_phase,内部的两阶段状态也会暂时保持为 “pending”,直到初始化阶段完成。要了解实际的两阶段状态, 请参见 pg_subscription 的subtwophasestate列。
disable_on_error (boolean) #指定如果订阅工作进程在从发布者复制数据期间检测到任何错误,是否自动 禁用该订阅。默认值为false。
password_required (boolean) #如果设为true,则由于该订阅而建立的到发布者的连接 必须使用密码认证,并且密码必须作为连接字符串的一部分指定。如果该订阅 由超级用户拥有,则此设置会被忽略。默认值为true。 只有超级用户才能将该值设为false。
run_as_owner (boolean) #如果为true,所有复制操作都以订阅所有者的身份执行。 如果为false,复制工作进程会在每张表上以该表所有者 的身份执行操作。后一种配置通常安全得多;详情请参见 Section 29.11。 默认值为false。
origin (string) #指定订阅是请求发布者仅发送没有复制源的更改,还是无论复制源如何都发送更改。 将origin设为none表示订阅会请求 发布者仅发送没有复制源的更改。将origin设为 any表示发布者无论复制源如何都发送更改。默认值为 any。
关于copy_data = true如何与 origin参数相互作用的细节,请参见 Notes。
failover (boolean) #指定与该订阅关联的复制槽是否启用同步到备库,以便在故障切换后 能够从新的主库继续逻辑复制。默认值为false。
指定boolean类型的参数时, = value 部分可以省略,这等价于指定TRUE。
关于如何在订阅与发布实例之间配置访问控制,详见 Section 29.11。
当创建复制槽时(这是默认行为),CREATE SUBSCRIPTION不能在事务块内部执行。
创建一个连接到同一数据库集簇的订阅(例如在同一集簇中的不同数据库之间 复制,或者在同一数据库内复制)时,只有在复制槽不作为同一命令的一部分 创建的情况下才会成功。否则,CREATE SUBSCRIPTION 调用将挂起。要实现这种用法,应分别创建复制槽(使用函数 pg_create_logical_replication_slot并指定插件名 pgoutput),然后使用参数 create_slot = false创建订阅。示例见 Section 29.2.3。 这是一个实现限制,未来版本中可能会解除。
如果发布中的任何表带有WHERE子句,则对 expression求值为 false或NULL的行不会被发布。 如果订阅包含多个发布,且同一张表在这些发布中使用了不同的 WHERE子句,那么只要任意一个表达式(针对相应的 发布操作)满足,该行就会被发布。对于不同的 WHERE子句,如果其中某个发布没有 WHERE子句(针对相应的发布操作),或者该发布被声明为 FOR ALL TABLES 或 FOR TABLES IN SCHEMA, 则无论其他表达式如何定义,该行都会被发布。如果订阅者使用的是 15 之前 版本的PostgreSQL,那么在初始数据同步阶段 会忽略所有行过滤。在这种情况下,用户可能需要考虑删除那些初始复制过来、 但与后续过滤不兼容的数据。由于初始数据同步在复制现有表数据时不会考虑 发布的 publish 参数,因此有些使用 DML 时本不会复制的行,也可能在此阶段被复制。示例见 Section 29.2.2。
如果订阅包含多个发布,而其中同一张表使用了不同的列列表进行发布,则不受支持。
允许指定不存在的发布,以便用户稍后再创建这些发布。这意味着 pg_subscription 中可能包含不存在的发布。
当使用copy_data = true和 origin = NONE这一订阅参数组合时,初始同步的表数据会 直接从发布者复制过来,因此无法得知这些数据的真实来源。如果发布者本身 也有订阅,那么复制过来的表数据可能来自更上游。系统会检测到这种情况, 并向用户记录一条WARNING,但这条警告只表明可能存在问题;用户仍需 自行进行必要检查,以确认复制过来的数据来源是否确实符合预期。
若要找出哪些表可能包含非本地来源的数据(由于在发布者上创建了其他订阅), 可以尝试执行以下 SQL 查询:
# substitute <pub-names> below with your publication name(s) to be queried
SELECT DISTINCT PT.schemaname, PT.tablename
FROM pg_publication_tables PT
JOIN pg_class C ON (C.relname = PT.tablename)
JOIN pg_namespace N ON (N.nspname = PT.schemaname),
pg_subscription_rel PS
WHERE C.relnamespace = N.oid AND
(PS.srrelid = C.oid OR
C.oid IN (SELECT relid FROM pg_partition_ancestors(PS.srrelid) UNION
SELECT relid FROM pg_partition_tree(PS.srrelid))) AND
PT.pubname IN (<pub-names>);
创建一个指向远端服务器的订阅,复制发布 mypublication和insert_only中的表, 并在提交时立即开始复制:
CREATE SUBSCRIPTION mysub
CONNECTION 'host=192.168.1.50 port=5432 user=foo dbname=foodb'
PUBLICATION mypublication, insert_only;
创建一个指向远端服务器的订阅,复制insert_only发布中的表, 并且要等到稍后启用时才开始复制。
CREATE SUBSCRIPTION mysub
CONNECTION 'host=192.168.1.50 port=5432 user=foo dbname=foodb'
PUBLICATION insert_only
WITH (enabled = false);
CREATE SUBSCRIPTION是 PostgreSQL扩展。
如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。