mirror of
https://github.com/postgres/postgres.git
synced 2025-07-27 12:41:57 +03:00
Add eager and lazy freezing strategies to VACUUM.
Eager freezing strategy avoids large build-ups of all-visible pages. It makes VACUUM trigger page-level freezing whenever doing so will enable the page to become all-frozen in the visibility map. This is useful for tables that experience continual growth, particularly strict append-only tables such as pgbench's history table. Eager freezing significantly improves performance stability by spreading out the cost of freezing over time, rather than doing most freezing during aggressive VACUUMs. It complements the insert autovacuum mechanism added by commitb07642db
. VACUUM determines its freezing strategy based on the value of the new vacuum_freeze_strategy_threshold GUC (or reloption) with logged tables. Tables that exceed the size threshold use the eager freezing strategy. Unlogged tables and temp tables always use eager freezing strategy, since the added cost is negligible there. Non-permanent relations won't incur any extra overhead in WAL written (for the obvious reason), nor in pages dirtied (since any extra freezing will only take place on pages whose PD_ALL_VISIBLE bit needed to be set either way). VACUUM uses lazy freezing strategy for logged tables that fall under the GUC size threshold. Page-level freezing triggers based on the criteria established in commit1de58df4
, which added basic page-level freezing. Eager freezing is strictly more aggressive than lazy freezing. Settings like vacuum_freeze_min_age still get applied in just the same way in every VACUUM, independent of the strategy in use. The only mechanical difference between eager and lazy freezing strategies is that only the former applies its own additional criteria to trigger freezing pages. Note that even lazy freezing strategy will trigger freezing whenever a page happens to have required that an FPI be written during pruning, provided that the page will thereby become all-frozen in the visibility map afterwards (due to the FPI optimization from commit1de58df4
). The vacuum_freeze_strategy_threshold default setting is 4GB. This is a relatively low setting that prioritizes performance stability. It will be reviewed at the end of the Postgres 16 beta period. Author: Peter Geoghegan <pg@bowt.ie> Reviewed-By: Jeff Davis <pgsql@j-davis.com> Reviewed-By: Andres Freund <andres@anarazel.de> Reviewed-By: Matthias van de Meent <boekewurm+postgres@gmail.com> Discussion: https://postgr.es/m/CAH2-WzkFok_6EAHuK39GaW4FjEFQsY=3J0AAd6FXk93u-Xq3Fg@mail.gmail.com
This commit is contained in:
@ -153,6 +153,8 @@ typedef struct LVRelState
|
||||
bool aggressive;
|
||||
/* Use visibility map to skip? (disabled by DISABLE_PAGE_SKIPPING) */
|
||||
bool skipwithvm;
|
||||
/* Eagerly freeze pages that are eligible to become all-frozen? */
|
||||
bool eager_freeze_strategy;
|
||||
/* Wraparound failsafe has been triggered? */
|
||||
bool failsafe_active;
|
||||
/* Consider index vacuuming bypass optimization? */
|
||||
@ -243,6 +245,7 @@ typedef struct LVSavedErrInfo
|
||||
|
||||
/* non-export function prototypes */
|
||||
static void lazy_scan_heap(LVRelState *vacrel);
|
||||
static void lazy_scan_strategy(LVRelState *vacrel);
|
||||
static BlockNumber lazy_scan_skip(LVRelState *vacrel, Buffer *vmbuffer,
|
||||
BlockNumber next_block,
|
||||
bool *next_unskippable_allvis,
|
||||
@ -472,6 +475,10 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
|
||||
|
||||
vacrel->skipwithvm = skipwithvm;
|
||||
|
||||
/*
|
||||
* Now determine VACUUM's freezing strategy
|
||||
*/
|
||||
lazy_scan_strategy(vacrel);
|
||||
if (verbose)
|
||||
{
|
||||
if (vacrel->aggressive)
|
||||
@ -1267,6 +1274,38 @@ lazy_scan_heap(LVRelState *vacrel)
|
||||
lazy_cleanup_all_indexes(vacrel);
|
||||
}
|
||||
|
||||
/*
|
||||
* lazy_scan_strategy() -- Determine freezing strategy.
|
||||
*
|
||||
* Our lazy freezing strategy is useful when putting off the work of freezing
|
||||
* totally avoids freezing that turns out to have been wasted effort later on.
|
||||
* Our eager freezing strategy is useful with larger tables that experience
|
||||
* continual growth, where freezing pages proactively is needed just to avoid
|
||||
* falling behind on freezing (eagerness is also likely to be cheaper in the
|
||||
* short/medium term for such tables, but the long term picture matters most).
|
||||
*/
|
||||
static void
|
||||
lazy_scan_strategy(LVRelState *vacrel)
|
||||
{
|
||||
BlockNumber rel_pages = vacrel->rel_pages;
|
||||
|
||||
/*
|
||||
* Decide freezing strategy.
|
||||
*
|
||||
* The eager freezing strategy is used whenever rel_pages exceeds a
|
||||
* threshold controlled by the freeze_strategy_threshold GUC/reloption.
|
||||
*
|
||||
* Also freeze eagerly with an unlogged or temp table, where the total
|
||||
* cost of freezing pages is mostly just the cycles needed to prepare a
|
||||
* set of freeze plans. Executing the freeze plans adds very little cost.
|
||||
* Dirtying extra pages isn't a concern, either; VACUUM will definitely
|
||||
* set PD_ALL_VISIBLE on affected pages, regardless of freezing strategy.
|
||||
*/
|
||||
vacrel->eager_freeze_strategy =
|
||||
(rel_pages > vacrel->cutoffs.freeze_strategy_threshold_pages ||
|
||||
!RelationIsPermanent(vacrel->rel));
|
||||
}
|
||||
|
||||
/*
|
||||
* lazy_scan_skip() -- set up range of skippable blocks using visibility map.
|
||||
*
|
||||
@ -1795,10 +1834,12 @@ retry:
|
||||
* one XID/MXID from before FreezeLimit/MultiXactCutoff is present. Also
|
||||
* freeze when pruning generated an FPI, if doing so means that we set the
|
||||
* page all-frozen afterwards (might not happen until final heap pass).
|
||||
* When ongoing VACUUM opted to use the eager freezing strategy we freeze
|
||||
* any page that will thereby become all-frozen in the visibility map.
|
||||
*/
|
||||
if (pagefrz.freeze_required || tuples_frozen == 0 ||
|
||||
(prunestate->all_visible && prunestate->all_frozen &&
|
||||
fpi_before != pgWalUsage.wal_fpi))
|
||||
(fpi_before != pgWalUsage.wal_fpi || vacrel->eager_freeze_strategy)))
|
||||
{
|
||||
/*
|
||||
* We're freezing the page. Our final NewRelfrozenXid doesn't need to
|
||||
|
Reference in New Issue
Block a user