PostgresQL:整个事务是否总是写入复制槽?

PostgresQL: Is an entire transaction always written to a replication slot?

我已经创建了一个复制槽:

SELECT * FROM pg_create_logical_replication_slot('boxoffice_slot', 'test_decoding');

事务中的每个步骤在复制槽中都有自己的行。这是一个例子:

     lsn     |   xid   |     data
-------------+---------+---------------
 34A/7000028 | 1311904 | BEGIN 1311904
 34A/70020E0 | 1311904 | table cad.purchases: INSERT: id[integer]:754862
 34A/70020E1 | 1311904 | table cad.purchases: INSERT: id[integer]:754863
 34A/7000028 | 1311904 | COMMIT 1311904

问题:
在事务生命周期的什么时候事务步骤开始写入复制槽?

是否可以在提交事务之前将事务步骤写入复制槽?

换句话说,是否有可能在任何给定时间只有一半事务写入复制槽,如下所示:

     lsn     |   xid   |     data
-------------+---------+---------------
 34A/7000028 | 1311904 | BEGIN 1311904
 34A/70020E0 | 1311904 | table cad.purchases: INSERT: id[integer]:754862

非常感谢您对此的见解。

事务中的所有内容都会在事务发生时写入复制槽。如果事务被回滚,则回滚被输入到 WAL 中。如果流在事务中间中断,则事务不会在订阅者端提交,至少在重新建立连接之前不会。

测试这个的一种方法是创建一个复制槽,然后在另一个终端中,使用 pg_recvlogical:

查看更改

pg_recvlogical -d postgres --slot <slot_name> --start --verbose -f -

如果您 BEGIN 一个事务,创建一个 table 并向其中插入一百万行,您会看到 write up toflush to 值在增加,即使交易没有得到 committed/rolled 回来。这告诉我们更改正在传播到接收端:

# pg_recvlogical -d postgres --slot regression_slot --start --verbose -f -
pg_recvlogical: starting log streaming at 0/0 (slot regression_slot)
pg_recvlogical: streaming initiated
pg_recvlogical: confirming write up to 0/0, flush to 0/0 (slot regression_slot)
pg_recvlogical: confirming write up to 0/DF5E620, flush to 0/DF5E620 (slot regression_slot)
pg_recvlogical: confirming write up to 0/DF5E620, flush to 0/DF5E620 (slot regression_slot)
pg_recvlogical: confirming write up to 0/12E01AB8, flush to 0/12E01AB8 (slot regression_slot)
pg_recvlogical: confirming write up to 0/12E01AF0, flush to 0/12E01AF0 (slot regression_slot)

此外,如果您在交易结束前后在您的终端中查看 pg_current_wal_lsn(),您将看到 LSN 增加,即使您回滚了:

 pg_current_wal_lsn 
--------------------
 0/DF5E620
(1 row)

postgres=# begin;
BEGIN
postgres=# select pg_current_wal_lsn();
 pg_current_wal_lsn 
--------------------
 0/DF5E620
(1 row)

postgres=# insert into abc values (generate_series(1,1000000),'foobar');
INSERT 0 1000000
postgres=# select pg_current_wal_lsn();
 pg_current_wal_lsn 
--------------------
 0/1243C000
(1 row)

postgres=# rollback;
ROLLBACK
postgres=# select pg_current_wal_lsn();
 pg_current_wal_lsn 
--------------------
 0/12E01AB8
(1 row)

交易根本没有写入复制槽。它们被写入 WAL。肯定会发生只有部分事务写入 WAL 的情况,例如,如果处理被中断。

部分写入的事务将在会话结束时自动标记为回滚(如果服务器崩溃,则在恢复期间)。

复制槽保存的数据不超过 LSN(日志序列号)。它们是在 WAL 中标记位置的持久数据结构。这样主服务器就不会丢弃消费者仍然需要的任何 WAL。当消费者处理 WAL 时,它会推进复制槽的 LSN,以便主可以丢弃已经使用的 WAL。

根据以下测试我得出结论,事务只有在提交后才会插入到复制槽中。

testing=# BEGIN;
BEGIN
testing=# SELECT * FROM pg_logical_slot_get_changes('testing_slot', NULL, NULL);
 lsn | xid | data
-----+-----+------
(0 rows)

testing=# insert into person values (generate_series(1,10));
INSERT 0 10
testing=# SELECT * FROM pg_logical_slot_get_changes('testing_slot', NULL, NULL);
 lsn | xid | data
-----+-----+------
(0 rows)

testing=# COMMIT;
COMMIT
testing=# SELECT * FROM pg_logical_slot_get_changes('testing_slot', NULL, NULL);
    lsn     |   xid    |                           data
------------+----------+-----------------------------------------------------------
 D/23426BC0 | 16171153 | BEGIN 16171153
 D/23426BC0 | 16171153 | table public.person: INSERT: name[character varying]:'1'
 D/23427078 | 16171153 | table public.person: INSERT: name[character varying]:'2'
 D/234270B8 | 16171153 | table public.person: INSERT: name[character varying]:'3'
 D/234270F8 | 16171153 | table public.person: INSERT: name[character varying]:'4'
 D/23427138 | 16171153 | table public.person: INSERT: name[character varying]:'5'
 D/23427178 | 16171153 | table public.person: INSERT: name[character varying]:'6'
 D/234271B8 | 16171153 | table public.person: INSERT: name[character varying]:'7'
 D/234271F8 | 16171153 | table public.person: INSERT: name[character varying]:'8'
 D/23427238 | 16171153 | table public.person: INSERT: name[character varying]:'9'
 D/23427278 | 16171153 | table public.person: INSERT: name[character varying]:'10'
 D/23427320 | 16171153 | COMMIT 16171153
(12 rows)