I'm trying to find out whether changes are reflected on the WAL (write ahead log) files if there is no change to a row. To test it, I create a replication slot in PostgreSQL to capture changes. Here are the steps I've taken.
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);
Then I execute SELECT * FROM pg_logical_slot_get_changes('slotname', NULL, NULL);
in psql (previous changes omitted)
The output is:
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)
Then I execute UPDATE foo SET col2=2 WHERE col1=1;
. Then the output of select * from pg_logical_slot_get_changes('slotname', null, null);
is:
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)
It looks like the UPDATE
statement has updated the WAL files even though it has no effect on the table. But where I'm confused is, if we look at the PostgreSQL docs for version 12 which is the version I'm using, it says in the "REPLICA IDENTITY" section that,
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.
The last sentence states that the old and the new versions of a row must differ to get logged. But I'm seeing the opposite. What am I missing here?