Re: New IndexAM API controlling index vacuum strategies - Mailing list pgsql-hackers

From Peter Geoghegan
Subject Re: New IndexAM API controlling index vacuum strategies
Date
Msg-id CAH2-Wzn6a64PJM1Ggzm=uvx2otsopJMhFQj_g1rAj4GWr3ZSzw@mail.gmail.com
Whole thread Raw
In response to Re: New IndexAM API controlling index vacuum strategies  (Peter Geoghegan <pg@bowt.ie>)
Responses Re: New IndexAM API controlling index vacuum strategies
Re: New IndexAM API controlling index vacuum strategies
List pgsql-hackers
On Thu, Apr 1, 2021 at 8:25 PM Peter Geoghegan <pg@bowt.ie> wrote:
> I've also found a way to further simplify the table-without-indexes
> case: make it behave like a regular two-pass/has-indexes VACUUM with
> regard to visibility map stuff when the page doesn't need a call to
> lazy_vacuum_heap() (because there are no LP_DEAD items to set
> LP_UNUSED on the page following pruning). But when it does call
> lazy_vacuum_heap(), the call takes care of everything for
> lazy_scan_heap(), which just continues to the next page due to
> considering prunestate to have been "invalidated" by the call to
> lazy_vacuum_heap(). So there is absolutely minimal special case code
> for the table-without-indexes case now.

Attached is v10, which simplifies the one-pass/table-without-indexes
VACUUM as described.

Other changes (some of which are directly related to the
one-pass/table-without-indexes refactoring):

* The second patch no longer breaks up lazy_scan_heap() into multiple
functions -- we only retain the lazy_scan_prune() function, which is
the one that I find very compelling.

This addresses Robert's concern about the functions -- I think that
it's much better this way, now that I see it.

* No more diff churn in the first patch. This was another concern held
by Robert, as well as by Masahiko.

In general both the first and second patches are much easier to follow now.

* The emergency mechanism is now able to kick in when we happen to be
doing a one-pass/table-without-indexes VACUUM -- no special
cases/"weasel words" are needed.

* Renamed "onerel" to "rel" in the first patch, per Robert's suggestion.

* Fixed various specific issues raised by Masahiko's review,
particularly in the first patch and last patch in the series.

Finally, there is a new patch added to the series in v10:

* I now include a modified version of Matthias van de Meent's line
pointer truncation patch [1].

Matthias' patch seems very much in scope here. The broader patch
series establishes the principle that we can leave LP_DEAD line
pointers in an unreclaimed state indefinitely, without consequence
(beyond the obvious).  We had better avoid line pointer bloat that
cannot be reversed when VACUUM does eventually get around to doing a
second pass over the heap. This is another case where it seems prudent
to keep the costs understandable/linear -- page-level line pointer
bloat seems like a cost that increases in a non-linear fashion, which
undermines the whole idea of modelling when it's okay to skip
index/heap vacuuming. (Also, line pointer bloat sucks.)

Line pointer truncation doesn't happen during pruning, as it did in
Matthias' original patch. In this revised version, line pointer
truncation occurs during the second phase of VACUUM. There are several
reasons to prefer this approach. It seems both safer and more useful
that way (compared to the approach of doing line pointer truncation
during pruning). It also makes intuitive sense to do it this way, at
least to me -- the second pass over the heap is supposed to be for
"freeing" LP_DEAD line pointers.

Many workloads rely heavily on opportunistic pruning. With a workload
that benefits a lot from HOT (e.g. pgbench with heap fillfactor
reduced to 90), there are many LP_UNUSED line pointers, even though we
may never have a VACUUM that actually performs a second heap pass
(because LP_DEAD items cannot accumulate in heap pages). Prior to the
HOT commit in 2007, LP_UNUSED line pointers were strictly something
that VACUUM created from dead tuples. It seems to me that we should
only target the latter "category" of LP_UNUSED line pointers when
considering truncating the array -- we ought to leave pruning
(especially opportunistic pruning that takes place outside of VACUUM)
alone.

(That reminds me -- the second patch now makes VACUUM VERBOSE stop
reporting LP_UNUSED items, because it is so utterly
misleading/confusing -- it now reports on LP_DEAD items instead, which
will bring things in line with log_autovacuum output once the last
patch in the series is in. This is arguably an oversight in the HOT
commit made back in 2007 -- that work kind of created a second
distinct category of LP_UNUSED item that really is totally different,
but it didn't account for why that makes stats about LP_UNUSED items
impossible to reason about.)

Doing truncation during VACUUM's second heap pass this way also makes
the line pointer truncation mechanism more effective. The problem with
truncating the LP array during pruning is that we more or less never
prune when the page is 100% (not ~99%) free of non-LP_UNUSED items --
which is actually the most compelling case for line pointer array
truncation! You can see this with a workload that consists of
alternating range deletions and bulk insertions that reuse the same
space -- think of a queue pattern, or TPC-C's new_orders table. Under
this scheme, we catch that extreme (though important) case every time
-- because we consider LP_UNUSED items immediately after they become
LP_UNUSED.

[1] https://postgr.es/m/CAEze2WjgaQc55Y5f5CQd3L=eS5CZcff2Obxp=O6pto8-f0hC4w@mail.gmail.com
--
Peter Geoghegan

Attachment

pgsql-hackers by date:

Previous
From: Justin Pryzby
Date:
Subject: [PATCH] force_parallel_mode and GUC categories
Next
From: Peter Geoghegan
Date:
Subject: Re: Lowering the ever-growing heap->pd_lower