SQL COMMAND · 逻辑复制
CREATE SUBSCRIPTION
定义一个新的订阅
CREATE逻辑复制引入 10(基线)现存至 20 devel1 次语法变更
- 动词
CREATE- 对象
SUBSCRIPTION- 分组
- 逻辑复制
- 引入版本
- 10(基线)
- 状态
- 现存
- 语法变更次数
- 1
- 手册小节数
- 6
版本轨迹
相对 PostgreSQL 17 语法未变,正文有更新。
语法铁道图 PostgreSQL 18
沿轨道从左向右阅读,分岔表示选择,绕行表示可选,回环表示重复。方框为参数,点击带下划线的参数可展开子规则。
语法概要
CREATE SUBSCRIPTIONsubscription_nameCONNECTION 'conninfo' PUBLICATIONpublication_name[, ...] [ WITH (subscription_parameter[=value] [, ... ] ) ]
描述
参数
subscription_name新订阅的名称。
CONNECTION 'conninfo'定义如何连接到发布者数据库的libpq连接字符串。详情请参见第 32.1.1 节。
PUBLICATIONpublication_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时不会建立连接,因此不会订阅任何表。要启动复制,你必须手工创建复制槽、在需要时启用故障切换、启用订阅,并刷新订阅。示例见第 29.2.3 节。create_slot(boolean)指定该命令是否应在发布者上创建复制槽。默认值为
true。如果设为
false,则必须以其他方式自行创建发布者上的复制槽。示例见第 29.2.3 节。enabled(boolean)指定订阅是应当主动进行复制,还是仅完成设置但暂不启动。默认值为
true。slot_name(string)要使用的发布者上的复制槽名称。默认使用订阅名称作为槽名。
将
slot_name设为NONE表示该订阅不关联任何复制槽。这类订阅还必须同时将enabled和create_slot设为false。当你打算稍后手工创建复制槽时,可使用此设置。示例见第 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子句,将会影响被复制的数据。详情请参见注意。关于
copy_data = true如何与origin参数相互作用的细节,请参见注意。streaming(enum)指定是否为该订阅启用进行中事务的流式传输。默认值为
parallel,表示如果有可用的并行应用工作进程,接收到的更改会直接通过其中之一应用。如果没有空闲的并行应用工作进程可以处理流式事务,那么这些更改会写入临时文件,并在事务提交后再应用。注意,如果并行应用工作进程中发生错误,远端事务的完成 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,复制工作进程会在每张表上以该表所有者的身份执行操作。后一种配置通常安全得多;详情请参见第 29.11 节。默认值为false。origin(string)指定订阅是请求发布者仅发送没有复制源的更改,还是无论复制源如何都发送更改。将
origin设为none表示订阅会请求发布者仅发送没有复制源的更改。将origin设为any表示发布者无论复制源如何都发送更改。默认值为any。关于
copy_data = true如何与origin参数相互作用的细节,请参见注意。failover(boolean)指定与该订阅关联的复制槽是否启用同步到备库,以便在故障切换后能够从新的主库继续逻辑复制。默认值为
false。
当指定boolean类型的参数时,可以省略 = value 部分,这等价于指定TRUE。
注解
关于如何在订阅与发布实例之间配置访问控制,详见第 29.11 节。
当创建复制槽时(这是默认行为),CREATE SUBSCRIPTION不能在事务块内部执行。
创建一个连接到同一数据库集簇的订阅(例如在同一集簇中的不同数据库之间复制,或者在同一数据库内复制)时,只有在复制槽不作为同一命令的一部分创建的情况下才会成功。否则,CREATE SUBSCRIPTION 调用将挂起。要实现这种用法,应分别创建复制槽(使用函数 pg_create_logical_replication_slot并指定插件名 pgoutput),然后使用参数 create_slot = false创建订阅。示例见第 29.2.3 节。这是一个实现限制,未来版本中可能会解除。
如果发布中的任何表带有WHERE子句,则对 expression求值为 false或NULL的行不会被发布。如果订阅包含多个发布,且同一张表在这些发布中使用了不同的 WHERE子句,那么只要任意一个表达式(针对相应的发布操作)满足,该行就会被发布。对于不同的 WHERE子句,如果其中某个发布没有 WHERE子句(针对相应的发布操作),或者该发布被声明为 FOR ALL TABLES 或 FOR TABLES IN SCHEMA,则无论其他表达式如何定义,该行都会被发布。如果订阅者使用的是 15 之前版本的PostgreSQL,那么在初始数据同步阶段会忽略所有行过滤。在这种情况下,用户可能需要考虑删除那些初始复制过来、但与后续过滤不兼容的数据。由于初始数据同步在复制现有表数据时不会考虑发布的 publish 参数,因此有些使用 DML 时本不会复制的行,也可能在此阶段被复制。示例见第 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扩展。
另见
语法演化
相邻大版本之间的差异,新的在前。版本号链接到对应快照。
PostgreSQL 20← 19正文更新
正文更新PostgreSQL 19← 18语法变化
+ { SERVER server_name | CONNECTION 'conninfo' }正文更新PostgreSQL 18← 17正文更新
正文更新PostgreSQL 17← 16正文更新
正文更新PostgreSQL 16← 15正文更新
正文更新PostgreSQL 15← 14正文更新
正文更新PostgreSQL 14← 13正文更新
正文更新PostgreSQL 12← 11正文更新
正文更新PostgreSQL 11← 10正文更新
正文更新
同组命令
| 命令 | 动词 | 对象 | 版本变动 | 最近变更 |
|---|---|---|---|---|
CREATE PUBLICATION | CREATE | PUBLICATION | 192 次 | |
| 定义一个新的发布 | 现存 | |||
ALTER PUBLICATION | ALTER | PUBLICATION | 193 次 | |
| 修改发布的定义 | 现存 | |||
DROP PUBLICATION | DROP | PUBLICATION | — | |
| 移除一个发布 | 现存 | |||
CREATE SUBSCRIPTION | CREATE | SUBSCRIPTION | 191 次 | |
| 定义一个新的订阅 | 现存 | |||
ALTER SUBSCRIPTION | ALTER | SUBSCRIPTION | 193 次 | |
| 修改订阅的定义 | 现存 | |||
DROP SUBSCRIPTION | DROP | SUBSCRIPTION | — | |
| 移除一个订阅 | 现存 | |||