SQL COMMAND · 事务控制
WAIT FOR
等待 WAL 达到目标 LSN
WAIT事务控制引入 19现存至 20 devel0 次语法变更
- 动词
WAIT- 对象
FOR- 分组
- 事务控制
- 引入版本
- 19
- 状态
- 现存
- 语法变更次数
- 0
- 手册小节数
- 5
版本轨迹
相对 PostgreSQL 19 语法未变,正文有更新。手册文件由 sql-wait-for.html 改为 sql-waitfor.html。
PostgreSQL 20 devel 尚未正式发布;本页来自对应手册快照,内容仍可能变化。
语法铁道图 PostgreSQL 20
沿轨道从左向右阅读,分岔表示选择,绕行表示可选,回环表示重复。方框为参数,点击带下划线的参数可展开子规则。
option
mode
语法概要
WAIT FOR LSN 'lsn' [ WITH (option[, ...] ) ] 其中option可以是: MODE 'mode' TIMEOUT 'timeout' NO_THROW 而mode可以是: standby_replay | standby_write | standby_flush | primary_flush
描述
等待直到根据指定的 mode 达到指定的 lsn, 该模式决定等待 WAL 被写入、刷盘还是重放。 如果没有指定 timeout,或者其值为零,则此命令会无限期等待 lsn。
超时时会发出错误,除非在 WITH 子句中指定了 NO_THROW。 对于备库模式(standby_replay、standby_write、 standby_flush),如果在达到 lsn 之前服务器被提升, 也会发出错误。如果指定了 NO_THROW,命令会返回一个状态字符串,而不是抛出错误。
可能的返回值是 success、timeout 和 not in recovery。
参数
lsn指定要等待的目标 LSN。
WITH (option[, ...] )此子句指定等待操作的可选参数。支持以下参数:
MODE'mode'指定要等待的 LSN 处理类型。如果未指定,默认值为
standby_replay。有效模式如下:standby_replay:等待该 LSN 在备库上被重放(应用到数据库)。 成功完成后,pg_last_wal_replay_lsn()将返回大于或等于目标 LSN 的值。 此模式只能在恢复期间使用。standby_write:等待包含该 LSN 的 WAL 被写入备库磁盘, 但不一定已经刷盘。这比standby_flush更快,但持久性保证更弱, 因为数据可能仍在操作系统缓冲区中。备库上已有的 WAL(来自基础备份、 归档恢复或先前的流式传输)以及从主库新接收的 WAL 均可满足此条件。 此模式只能在恢复期间使用。standby_flush:等待包含该 LSN 的 WAL 在备库上刷盘。 这提供了持久性保证,而无需等待 WAL 被应用。备库上已有的 WAL(来自基础备份、 归档恢复或先前的流式传输)以及从主库新接收的 WAL 均可满足此条件。 此模式只能在恢复期间使用。primary_flush:等待包含该 LSN 的 WAL 在主库上刷盘。 成功完成后,pg_current_wal_flush_lsn()将返回大于或等于目标 LSN 的值。 此模式只能在主库上使用(不能在恢复期间使用)。
TIMEOUT'timeout'在指定且
timeout大于零时,命令会一直等待到lsn达到,或者直到指定的timeout到期为止。timeout可以给定为整数毫秒数。 也可以给定为字符串字面量,表示整数毫秒数,或者带单位的数值 (见 Section 19.1.1)。NO_THROW指定在超时或在主库上运行时不抛出错误。在这种情况下,可以从返回值中获取结果状态。
输出
success此返回值表示已成功达到目标
lsn。timeout此返回值表示在达到目标
lsn之前发生了超时。not in recovery此返回值表示数据库服务器不处于恢复状态。 这可能意味着数据库服务器在接收到命令时并不处于恢复状态(即在主库上执行), 也可能意味着它在达到目标
lsn之前被提升。 在提升的情况下,此状态表示发生了时间线变更,应用程序应重新评估目标 LSN 是否仍然适用。
备注
WAIT FOR 必须作为顶层命令执行。 它不能在函数、过程或 DO 块中执行。 它还要求不存在活动或已注册的快照,因此不能在必须保持此类快照处于活动状态的上下文中使用, 包括隔离级别高于 READ COMMITTED 的事务。
WAIT FOR 会根据指定的 mode 一直等待直到达到指定的 lsn。standby_replay 模式会等待该 LSN 被回放(应用到数据库), 这有助于在使用异步副本读取和主库写入时实现读己之写一致性。 standby_flush 模式会等待 WAL 在副本上刷入持久存储,或者等待备库上已有的 WAL 已被回放。 standby_write 模式会等待 WAL 被写入操作系统,或者已经回放;对于新接收的 WAL, 这比刷盘更快,但持久性保证更弱。 primary_flush 模式会等待 WAL 在主库上刷盘。 在所有情况下,最后一次修改的 LSN 应当存储在客户端应用程序一侧或连接池一侧。
备库模式(standby_replay、standby_write、 standby_flush)只能在恢复期间使用,而 primary_flush 只能在主库上使用。对当前服务器状态使用错误的模式会导致错误。 如果在使用备库模式等待期间备库被提升,命令将返回 not in recovery(或者在未指定 NO_THROW 时抛出错误)。提升会创建新的时间线,而正在等待的 LSN 可能指向旧时间线中的 WAL。
WAIT FOR只比较LSN数值;它并不知道 WAL 记录属于哪条时间线。 当备库跨上游时间线切换继续恢复时,这一点很重要—例如,级联备库的上游被提升。 在这种情况下,只要所选等待模式使用的位置达到或超过该LSN数值, WAIT FOR就会返回success,而不考虑该 LSN属于哪条时间线。需要确认目标指向预期时间线的应用程序必须自行验证时间线。
在备库服务器上,WAIT FOR 会话可能会被恢复冲突中断。 某些恢复冲突是不可避免的:例如,回放一个表空间删除操作时,无论后端正在执行什么,都会通过终止所有后端来解决冲突。 在备库上使用 WAIT FOR 的应用程序应准备好处理此类中断,例如通过重试命令或回退到其他机制。
示例
可以使用 WAIT FOR 命令等待 pg_lsn 值。 例如,应用程序可以更新 movie 表,并在刚刚完成更改后获取 lsn。 由于 synchronous_commit 可能设置为 off,此示例在主库上使用 pg_current_wal_insert_lsn 获取 lsn。
postgres=# UPDATE movie SET genre = 'Dramatic' WHERE genre = 'Drama'; UPDATE 100 postgres=# SELECT pg_current_wal_insert_lsn(); pg_current_wal_insert_lsn --------------------------- 0/0306EE20 (1 row)
然后,应用程序可以使用从主库获得的 lsn 运行 WAIT FOR。 之后,主库上所做的更改应当保证在副本上可见。
postgres=# WAIT FOR LSN '0/0306EE20'; status --------- success (1 row) postgres=# SELECT * FROM movie WHERE genre = 'Drama'; genre ------- (0 rows)
等待刷盘(数据在副本上持久化):
postgres=# WAIT FOR LSN '0/0306EE20' WITH (MODE 'standby_flush'); status --------- success (1 row)
带超时的等待写入:
postgres=# WAIT FOR LSN '0/0306EE20' WITH (MODE 'standby_write', TIMEOUT '100ms', NO_THROW); status --------- success (1 row)
等待主库刷盘:
postgres=# WAIT FOR LSN '0/0306EE20' WITH (MODE 'primary_flush'); status --------- success (1 row)
如果在超时之前未达到目标 LSN,则会抛出错误:
postgres=# WAIT FOR LSN '0/0306EE20' WITH (TIMEOUT '0.1s'); ERROR: timed out while waiting for target LSN 0/0306EE20 to be replayed; current standby_replay LSN 0/0306EA60
同一个示例使用带 NO_THROW 选项的 WAIT FOR:
postgres=# WAIT FOR LSN '0/0306EE20' WITH (TIMEOUT '100ms', NO_THROW); status --------- timeout (1 row)
语法演化
相邻大版本之间的差异,新的在前。版本号链接到对应快照。
PostgreSQL 20← 19文件改名
sql-wait-for.html → sql-waitfor.html
正文更新PostgreSQL 19← 18新增此命令
同组命令
| 命令 | 动词 | 对象 | 版本变动 | 最近变更 |
|---|---|---|---|---|
ABORT | ABORT | — | 121 次 | |
| 中止当前事务 | 现存 | |||
BEGIN | BEGIN | — | — | |
| 开始一个事务块 | 现存 | |||
COMMIT | COMMIT | — | 121 次 | |
| 提交当前事务 | 现存 | |||
END | END | — | 121 次 | |
| 提交当前事务 | 现存 | |||
ROLLBACK | ROLLBACK | — | 121 次 | |
| 中止当前事务 | 现存 | |||
SAVEPOINT | SAVEPOINT | — | — | |
| 在当前事务中定义一个新的保存点 | 现存 | |||
SET CONSTRAINTS | SET | CONSTRAINTS | — | |
| 为当前事务设置约束检查时机 | 现存 | |||
WAIT FOR | WAIT | FOR | — | |
| 等待 WAL 达到目标 LSN | 现存 | |||
COMMIT PREPARED | COMMIT | PREPARED | — | |
| 提交一个先前为两阶段提交而预备的事务 | 现存 | |||
ROLLBACK PREPARED | ROLLBACK | PREPARED | — | |
| 回滚一个先前为两阶段提交而预备的事务 | 现存 | |||
RELEASE SAVEPOINT | RELEASE | SAVEPOINT | — | |
| 释放一个先前定义的保存点 | 现存 | |||
ROLLBACK TO SAVEPOINT | ROLLBACK | TO SAVEPOINT | — | |
| 回滚到一个保存点 | 现存 | |||
PREPARE TRANSACTION | PREPARE | TRANSACTION | — | |
| 为两阶段提交准备当前事务 | 现存 | |||
SET TRANSACTION | SET | TRANSACTION | — | |
| 设置当前事务的特性 | 现存 | |||
START TRANSACTION | START | TRANSACTION | — | |
| 开始一个事务块 | 现存 | |||