sql - 如果 PostgreSQL 没有变化,事务是否记录到 WAL?

标签 sql postgresql transactional-replication change-data-capture wal

如果行没有更改,我试图找出更改是否反射(reflect)在 WAL(预写日志)文件上。为了测试它,我在 PostgreSQL 中创建了一个复制槽来捕获更改。
这是我采取的步骤。

ALTER SYSTEM SET wal_level TO logical;
$ pg_ctl restart
SELECT pg_create_logical_replication_slot('slotname', 'test_decoding');
CREATE TABLE foo(col1 INTEGER, col2 INTEGER);
ALTER TABLE foo REPLICA IDENTITY FULL;
INSERT INTO foo VALUES(1,2);
然后我执行 SELECT * FROM pg_logical_slot_get_changes('slotname', NULL, NULL);在 psql 中(省略之前的更改)
输出是:
    lsn    | xid |                           data                            
-----------+-----+-----------------------------------------------------------
 0/165B208 | 488 | BEGIN 488
 0/165B208 | 488 | table public.foo: INSERT: col1[integer]:1 col2[integer]:2
 0/165B278 | 488 | COMMIT 488
(3 rows)
然后我执行 UPDATE foo SET col2=2 WHERE col1=1; .然后输出 select * from pg_logical_slot_get_changes('slotname', null, null);是:
    lsn    | xid |                                                     data                                                      
-----------+-----+---------------------------------------------------------------------------------------------------------------
 0/165B2B0 | 489 | BEGIN 489
 0/165B2B0 | 489 | table public.foo: UPDATE: old-key: col1[integer]:1 col2[integer]:2 new-tuple: col1[integer]:1 col2[integer]:2
 0/165B338 | 489 | COMMIT 489
(3 rows)
它看起来像 UPDATE语句已更新 WAL 文件,即使它对表没有影响。但我感到困惑的是,如果我们查看 PostgreSQL docs对于我正在使用的版本 12,它在“REPLICA IDENTITY”部分说,

REPLICA IDENTITY This form changes the information which is written to the write-ahead log to identify rows which are updated or deleted. This option has no effect except when logical replication is in use. DEFAULT (the default for non-system tables) records the old values of the columns of the primary key, if any. USING INDEX records the old values of the columns covered by the named index, which must be unique, not partial, not deferrable, and include only columns marked NOT NULL. FULL records the old values of all columns in the row. NOTHING records no information about the old row. (This is the default for system tables.) In all cases, no old values are logged unless at least one of the columns that would be logged differs between the old and new versions of the row.


最后一句指出行的旧版本和新版本必须不同才能被记录。但我看到了相反的情况。我在这里缺少什么?

最佳答案

Replica identity只是逻辑复制消息/协议(protocol)的一部分,参见 Message format :

Update ... Byte1('K')


Identifies the following TupleData submessage as a key. This field is optional and is only present if the update changed data in any of the column(s) that are part of the REPLICA IDENTITY index. Byte1('O')


Identifies the following TupleData submessage as an old tuple. This field is optional and is only present if table in which the update happened has REPLICA IDENTITY set to FULL.


您引用的文档部分是指上述内容。您显示的插槽信息正在查看整个复制过程。Replica identity的目的在这里详细说明 Logical replication :

A published table must have a “replica identity” configured in order to be able to replicate UPDATE and DELETE operations, so that appropriate rows to update or delete can be identified on the subscriber side. By default, this is the primary key, if there is one. Another unique index (with certain additional requirements) can also be set to be the replica identity. If the table does not have any suitable key, then it can be set to replica identity “full”, which means the entire row becomes the key. This, however, is very inefficient and should only be used as a fallback if no other solution is possible. If a replica identity other than “full” is set on the publisher side, a replica identity comprising the same or fewer columns must also be set on the subscriber side. See REPLICA IDENTITY for details on how to set the replica identity. If a table without a replica identity is added to a publication that replicates UPDATE or DELETE operations then subsequent UPDATE or DELETE operations will cause an error on the publisher. INSERT operations can proceed regardless of any replica identity.

关于sql - 如果 PostgreSQL 没有变化,事务是否记录到 WAL?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68334065/

相关文章:

sql - 在 Grails 2.3.x 中执行原始 SQL 查询时如何指定备用数据源?

postgresql - 列中的 Postgres-pgloader-transformation

sql-server - SQL Server 复制本地订阅属性返回 "Cannot apply value ‘null’ 到属性 ServerInstance : Value cannot be null. "

sql - 哪种数据类型最适合通过事务复制发布的表的聚集索引?

sql - 从客户事件、SQL 中查找放弃的搜索

sql-server - 无主键(唯一索引)的事务复制

mysql - 获取子查询 where 子句 id 与主查询中的 id 匹配

java - 在每次请求时刷新 session 中存储的用户帐户对象的最佳方法

php - 嵌套 SQL 查询,按分组并为每个组返回有限的行

python - (重新)从 "backup"表描述创建表