Combine Prune and Freeze records emitted by vacuum

From: Melanie Plageman <melanieplageman(at)gmail(dot)com>
To: Pg Hackers <pgsql-hackers(at)postgresql(dot)org>
Cc: Andres Freund <andres(at)anarazel(dot)de>, Robert Haas <robertmhaas(at)gmail(dot)com>, Heikki Linnakangas <hlinnaka(at)iki(dot)fi>, Peter Geoghegan <pg(at)bowt(dot)ie>
Subject: Combine Prune and Freeze records emitted by vacuum
Date: 2024-01-24 22:49:35
Message-ID: CAAKRu_azf-zH=DgVbquZ3tFWjMY1w5pO8m-TXJaMdri8z3933g@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi,

Attached is a patch set which combines the freeze and prune records
for vacuum -- eliminating the overhead of a separate freeze WAL record
for every block frozen by vacuum. The contents of the freeze record
are added to the PRUNE record.

In cases where vacuum does freeze and prune, combining the WAL records
can reduce WAL bytes substantially and, as a consequence, reduce WAL
sync and write time.

For example:

psql -c "CREATE TABLE foo(id INT, a INT, b INT, c INT, d INT, e INT, f
INT, g INT, h TEXT) WITH (autovacuum_enabled=false);"

for x in $(seq 1 16);
do
psql -c "INSERT INTO foo SELECT i, i, i, i, i, i, i, i, repeat('b',
30) FROM generate_series(1,2000000)i;"
done

psql -c "UPDATE foo SET a = 2 WHERE id % 7 = 0;"
psql -c "VACUUM (FREEZE) foo;"

Generates 30% fewer WAL records and 12% fewer WAL bytes -- which,
depending on what else is happening on the system, can lead to vacuum
spending substantially less time on WAL writing and syncing (often 15%
less time on WAL writes and 10% less time on syncing WAL in my
testing).

Though heap_page_prune() is also used by on-access pruning, on-access
pruning does not pass in the parameter used for freezing, so it should
incur limited additional overhead. The primary additional overhead
would be checking tuples' xmins against the GlobalVisState to
determine if the page would be all_visible and identify the visibility
cutoff xid. This is required to determine whether or not to
opportunistically freeze. We could condition this on the caller being
vacuum if needed.

Though, in the future, we may want to consider opportunistic/eager
freezing on access. This could allow us to, for example, freeze
bulk-loaded read-only data before it goes cold and avoid expensive
wraparound vacuuming.

There are other steps that we can take to decrease vacuum WAL volume
even further. Many of those are natural follow-ons to combining the
prune and freeze record. For example, I intend to propose combining
the visibility map update record into the Prune/Freeze and Vacuum
records -- eliminating an extra visibility map update record. This
would mean a single WAL record emitted per block for vacuum's first
pass.

On master, for my example above, of the roughly 1 million WAL records
emitted by vacuum, about 1/3 of them are prune records, 1/3 are freeze
records, and 1/3 are visibility map update records. So we will achieve
another substantial reduction in the number of WAL records and bytes
of WAL record overhead by eliminating a separate record for updating
the VM.

The attached patch set is broken up into many separate commits for
ease of review. Each patch does a single thing which can be explained
plainly in the commit message. Every commit passes tests and works on
its own.

0001 - 0003 cover checking tuples' xmins against the GlobalVisState in
heap_page_prune().

0004 - 0007 executes freezing in heap_page_prune() (for vacuum only).

0008 translates the eager/opportunistic freeze heuristic into one that
will work without relying on having a separate prune record. Elsewhere
in [1] we are discussing how to improve this heuristic.

0009 - 0012 merges the freeze record into the prune record.

0013 - 0015 removes the loop through the page in lazy_scan_prune() by
doing the accounting it did in heap_page_prune(). A nice bonus of this
patch set is that we can eliminate one of vacuum's loops through the
page.

- Melanie

[1] https://www.postgresql.org/message-id/CAAKRu_ZTDm1d9M%2BENf6oXhW9nRT3J76vOL1ianiCW4%2B4M6hMoA%40mail.gmail.com

Attachment Content-Type Size
v1-0004-Add-reference-to-VacuumCutoffs-in-HeapPageFreeze.patch text/x-patch 7.5 KB
v1-0001-lazy_scan_prune-tests-tuple-vis-with-GlobalVisTes.patch text/x-patch 1.7 KB
v1-0002-Pass-heap_prune_chain-PruneResult-output-paramete.patch text/x-patch 3.3 KB
v1-0003-heap_page_prune-sets-all_visible-and-frz_conflict.patch text/x-patch 18.4 KB
v1-0005-Prepare-freeze-tuples-in-heap_page_prune.patch text/x-patch 13.3 KB
v1-0006-lazy_scan_prune-reorder-freeze-execution-logic.patch text/x-patch 6.9 KB
v1-0009-Separate-tuple-pre-freeze-checks-and-invoke-earli.patch text/x-patch 5.6 KB
v1-0010-Inline-heap_freeze_execute_prepared.patch text/x-patch 8.4 KB
v1-0007-Execute-freezing-in-heap_page_prune.patch text/x-patch 9.9 KB
v1-0008-Make-opp-freeze-heuristic-compatible-with-prune-f.patch text/x-patch 4.3 KB
v1-0013-Set-hastup-in-heap_page_prune.patch text/x-patch 7.2 KB
v1-0014-Count-tuples-for-vacuum-logging-in-heap_page_prun.patch text/x-patch 14.8 KB
v1-0011-Exit-heap_page_prune-early-if-no-prune.patch text/x-patch 8.1 KB
v1-0012-Merge-prune-and-freeze-records.patch text/x-patch 8.8 KB
v1-0015-Save-dead-tuple-offsets-during-heap_page_prune.patch text/x-patch 7.0 KB

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message David E. Wheeler 2024-01-24 23:39:47 Re: Patch: Improve Boolean Predicate JSON Path Docs
Previous Message Kirk Wolak 2024-01-24 22:26:03 Re: Oom on temp (un-analyzed table caused by JIT) V16.1 [ NOT Fixed ]