受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发版本: 19 / devel
此文档适用于不受支持的 PostgreSQL 版本。
您可能需要查看当前版本的相同页面,或上面列出的其他受支持版本。

CREATE SUBSCRIPTION

CREATE SUBSCRIPTION — 定义一个新的订阅

Synopsis

CREATE SUBSCRIPTION subscription_name
    { SERVER servername | CONNECTION 'conninfo' }
    PUBLICATION publication_name [, ...]
    [ WITH ( subscription_parameter [= value] [, ... ] ) ]

描述

CREATE SUBSCRIPTION添加一个新的逻辑复制订阅。 创建订阅的用户将成为该订阅的所有者。订阅名称必须与当前数据库中 任何现有订阅的名称不同。

订阅表示与发布者的复制连接。因此,除了在本地系统目录中添加定义之外, 该命令通常还会在发布者上创建一个复制槽。

除非订阅初始即被禁用,否则在执行该命令所在事务提交时,会启动一个 逻辑复制工作进程为新订阅复制数据。

要能够创建订阅,必须具有pg_create_subscription角色的权限, 以及当前数据库上的CREATE权限。

关于订阅以及整个逻辑复制的更多信息,请参见 Section 29.2Chapter 29

参数

subscription_name #

新订阅的名称。

SERVER servername #

供连接使用的外部服务器。该服务器的外部数据包装器必须已注册 connection_function,并且该服务器上必须存在 订阅所有者的用户映射。此外,订阅所有者必须在 servername上具有USAGE权限。

CONNECTION 'conninfo' #

定义如何连接到发布者数据库的libpq连接字符串。 详情请参见Section 32.1.1

PUBLICATION publication_name [, ...] #

要订阅的发布者上的发布名称。

WITH ( subscription_parameter [= value] [, ... ] ) #

该子句为订阅指定可选参数。

下列参数控制订阅创建期间的行为:

connect (boolean) #

指定CREATE SUBSCRIPTION命令是否连接到 发布者。默认值为true。将其设为 false会强制把create_slotenabledcopy_data的值 设为false。(不能将connect 设为false的同时,再把create_slotenabledcopy_data设为 true。)

由于该选项为false时不会建立连接,因此不会订阅任何表和 序列。要启动复制,你必须手工创建复制槽、在需要时启用故障切换、启用订阅, 并刷新订阅。示例见 Section 29.2.3

create_slot (boolean) #

指定该命令是否应在发布者上创建复制槽。默认值为 true

如果设为false,则必须以其他方式自行创建 发布者上的复制槽。示例见 Section 29.2.3

enabled (boolean) #

指定订阅是应当主动进行复制,还是仅完成设置但暂不启动。 默认值为true

slot_name (string) #

要使用的发布者上的复制槽名称。默认使用订阅名称作为槽名。该名称不能为 pg_conflict_detection,因为它保留给冲突检测使用。

slot_name设为NONE表示该订阅 不关联任何复制槽。这类订阅还必须同时将enabledcreate_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

若要处理关于发布者与订阅者之间序列定义差异的任何警告,请参见 Section 29.7.1

streaming (enum) #

指定是否为该订阅启用进行中事务的流式传输。默认值为 parallel,表示如果有可用的并行应用工作进程, 接收到的更改会直接通过其中之一应用。如果没有空闲的并行应用工作进程 可以处理流式事务,那么这些更改会写入临时文件,并在事务提交后再应用。 注意,如果并行应用工作进程中发生错误,远端事务的 finish LSN 可能不会记录到服务器日志中。此参数对序列没有影响。

Caution

当发布者与订阅者的模式不同时,存在发生死锁的风险,尽管这种情况 很少见。应用工作进程会自动重试这些事务。

如果设为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_subscriptionsubtwophasestate列。

disable_on_error (boolean) #

指定如果订阅工作进程在从发布者复制数据期间检测到任何错误,是否自动 禁用该订阅。默认值为false

password_required (boolean) #

如果设为true,则由于该订阅而建立的到发布者的连接 必须使用密码认证,并且密码必须作为连接字符串的一部分指定。如果该订阅 由超级用户拥有,则此设置会被忽略。默认值为true。 只有超级用户才能将该值设为false

run_as_owner (boolean) #

如果为true,所有复制操作都以订阅所有者的身份执行。 如果为false,复制工作进程会在每张表或序列上以 该关系的所有者身份执行操作。后一种配置通常安全得多;详情请参见 Section 29.12。 默认值为false

origin (string) #

指定订阅是请求发布者仅发送没有复制源的更改,还是无论复制源如何都发送更改。 将origin设为none表示订阅会请求 发布者仅发送没有复制源的更改。将origin设为 any表示发布者无论复制源如何都发送更改。默认值为 any。此参数对序列没有影响。

关于copy_data = true如何与 origin参数相互作用的细节,请参见 Notes

failover (boolean) #

指定与该订阅关联的复制槽是否启用同步到备库,以便在故障切换后 能够从新的主库继续逻辑复制。默认值为false

retain_dead_tuples (boolean) #

指定是否保留订阅者上冲突检测所需的信息(例如死元组、提交时间戳和 来源)。默认值为false。如果设为 true,则会启用 update_deleted 的检测,并在订阅者上创建一个名为 pg_conflict_detection的物理复制槽,以防止 用于检测冲突的信息被移除。此参数对序列没有影响。

请注意,只有在创建该槽之后,才会保留用于冲突检测的信息。可以通过查询 pg_replication_slots来验证该槽 是否存在。即使同一节点上的多个订阅启用此选项,也只会创建一个复制槽。 此外,必须将wal_level设置为replica 或更高,才能允许使用该复制槽。

Caution

请注意,如果订阅被禁用,用于冲突检测的信息将无法被清除;因此,这些信息 会一直累积,直到订阅被启用。为了防止过度累积,建议在订阅将长时间处于 非活动状态时禁用retain_dead_tuples

此外,在逻辑复制中为冲突检测启用retain_dead_tuples时, 设计复制拓扑以平衡数据保留需求与整体系统性能非常重要。该选项在适当使用时 只会带来极小的性能开销。以下场景展示了启用该选项时的有效用法模式。

a. 双向写入的大表: 对于在发布者和订阅者节点上都存在并发写入的大表,发布者可以在创建发布时 定义行过滤器来分割数据。这样可以让多个订阅并行复制该表的互斥子集,从而 优化吞吐量。

b. 可写入的订阅者: 如果预期订阅者节点需要执行写操作,则可以通过多个发布和订阅来组织复制。 通过将表分配到这些发布中,工作负载会分散到多个应用工作进程之间,从而 提高并发性并减少争用。

c. 只读订阅者: 在涉及一个或多个发布者节点执行并发写操作的配置中,只读订阅者节点如果 执行的是索引扫描,则可能不会看到性能影响。然而,如果订阅者由于复制延迟 或扫描性能(例如顺序扫描)而受到影响,则需要采用前述两种策略之一来在 订阅者上分散负载。

如果发布者是物理备库,则不能启用此选项。

启用此选项只能保证保留用于冲突检测的信息,且仅针对在发布者本地发生的 更改。对于来自不同来源的更改,无法保证可靠的冲突检测。

max_retention_duration (integer) #

当启用retain_dead_tuples时,此订阅的应用工作进程允许 保留用于冲突检测的信息的最长时长,单位为毫秒。默认值为 0,表示在不再需要进行检测之前一直保留这些信息。

如果所有与启用了retain_dead_tuples的订阅相关联的应用 工作进程都确认保留时长已经超过相应订阅中设置的 max_retention_duration,则用于冲突检测的信息将不再 被保留。只要至少有一个应用工作进程确认保留时长仍在指定限制内,或者创建了 一个新的retain_dead_tuples = true订阅,保留就会自动 恢复。或者,也可以通过重新启用 retain_dead_tuples手工恢复保留。

注意,如果其他订阅为此参数设置了大于 0 的值且尚未超过该值,或者将此选项 设为0,则整体保留不会停止。

只有当启用了retain_dead_tuples且与该订阅关联的应用工作 进程处于活动状态时,此选项才有效。

Warning

注意,将此选项设为非零值可能导致用于冲突检测的信息被过早移除,从而可能 造成错误的冲突检测。

wal_receiver_timeout (text) #

该参数的值会覆盖此订阅应用工作进程中的 wal_receiver_timeout设置。默认值为 -1,表示不覆盖全局设置,也就是说将改用服务器配置、 命令行、角色或数据库设置中的值。

指定boolean类型的参数时, = value 部分可以省略,这等价于指定TRUE

注意

关于如何在订阅与发布实例之间配置访问控制,详见 Section 29.12

当创建复制槽时(这是默认行为),CREATE SUBSCRIPTION不能在事务块内部执行。

创建一个连接到同一数据库集簇的订阅(例如在同一集簇中的不同数据库之间 复制,或者在同一数据库内复制)时,只有在复制槽不作为同一命令的一部分 创建的情况下才会成功。否则,CREATE SUBSCRIPTION 调用将挂起。要实现这种用法,应分别创建复制槽(使用函数 pg_create_logical_replication_slot并指定插件名 pgoutput),然后使用参数 create_slot = false创建订阅。示例见 Section 29.2.3。 这是一个实现限制,未来版本中可能会解除。

如果发布中的任何表带有WHERE子句,则对 expression求值为 falseNULL的行不会被发布。 如果订阅包含多个发布,且同一张表在这些发布中使用了不同的 WHERE子句,那么只要任意一个表达式(针对相应的 发布操作)满足,该行就会被发布。对于不同的 WHERE子句,如果其中某个发布没有 WHERE子句(针对相应的发布操作),或者该发布被声明为 FOR ALL TABLESFOR TABLES IN SCHEMA, 则无论其他表达式如何定义,该行都会被发布。如果订阅者使用的是 15 之前 版本的PostgreSQL,那么在初始数据同步阶段 会忽略所有行过滤。在这种情况下,用户可能需要考虑删除那些初始复制过来、 但与后续过滤不兼容的数据。由于初始数据同步在复制现有表数据时不会考虑 发布的 publish 参数,因此有些使用 DML 时本不会复制的行,也可能在此阶段被复制。示例见 Section 29.2.2

如果订阅包含多个发布,而其中同一张表使用了不同的列列表进行发布,则不受支持。

允许指定不存在的发布,以便用户稍后再创建这些发布。这意味着 pg_subscription 中可能包含不存在的发布。

当使用copy_data = trueorigin = 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>);

示例

创建一个指向远端服务器的订阅,复制发布 mypublicationinsert_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 SUBSCRIPTIONPostgreSQL扩展。