mirror of
https://github.com/postgres/postgres.git
synced 2025-09-11 00:12:06 +03:00
Eagerly scan all-visible pages to amortize aggressive vacuum
Aggressive vacuums must scan every unfrozen tuple in order to advance the relfrozenxid/relminmxid. Because data is often vacuumed before it is old enough to require freezing, relations may build up a large backlog of pages that are set all-visible but not all-frozen in the visibility map. When an aggressive vacuum is triggered, all of these pages must be scanned. These pages have often been evicted from shared buffers and even from the kernel buffer cache. Thus, aggressive vacuums often incur large amounts of extra I/O at the expense of foreground workloads. To amortize the cost of aggressive vacuums, eagerly scan some all-visible but not all-frozen pages during normal vacuums. All-visible pages that are eagerly scanned and set all-frozen in the visibility map are counted as successful eager freezes and those not frozen are counted as failed eager freezes. If too many eager scans fail in a row, eager scanning is temporarily suspended until a later portion of the relation. The number of failures tolerated is configurable globally and per table. To effectively amortize aggressive vacuums, we cap the number of successes as well. Capping eager freeze successes also limits the amount of potentially wasted work if these pages are modified again before the next aggressive vacuum. Once we reach the maximum number of blocks successfully eager frozen, eager scanning is disabled for the remainder of the vacuum of the relation. Original design idea from Robert Haas, with enhancements from Andres Freund, Tomas Vondra, and me Reviewed-by: Robert Haas <robertmhaas@gmail.com> Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com> Reviewed-by: Andres Freund <andres@anarazel.de> Reviewed-by: Robert Treat <rob@xzilla.net> Reviewed-by: Bilal Yavuz <byavuz81@gmail.com> Discussion: https://postgr.es/m/flat/CAAKRu_ZF_KCzZuOrPrOqjGVe8iRVWEAJSpzMgRQs%3D5-v84cXUg%40mail.gmail.com
This commit is contained in:
@@ -69,6 +69,7 @@ int vacuum_multixact_freeze_min_age;
|
||||
int vacuum_multixact_freeze_table_age;
|
||||
int vacuum_failsafe_age;
|
||||
int vacuum_multixact_failsafe_age;
|
||||
double vacuum_max_eager_freeze_failure_rate;
|
||||
|
||||
/*
|
||||
* Variables for cost-based vacuum delay. The defaults differ between
|
||||
@@ -405,6 +406,11 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel)
|
||||
/* user-invoked vacuum uses VACOPT_VERBOSE instead of log_min_duration */
|
||||
params.log_min_duration = -1;
|
||||
|
||||
/*
|
||||
* Later, in vacuum_rel(), we check if a reloption override was specified.
|
||||
*/
|
||||
params.max_eager_freeze_failure_rate = vacuum_max_eager_freeze_failure_rate;
|
||||
|
||||
/*
|
||||
* Create special memory context for cross-transaction storage.
|
||||
*
|
||||
@@ -2165,6 +2171,15 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the vacuum_max_eager_freeze_failure_rate table storage
|
||||
* parameter was specified. This overrides the GUC value.
|
||||
*/
|
||||
if (rel->rd_options != NULL &&
|
||||
((StdRdOptions *) rel->rd_options)->vacuum_max_eager_freeze_failure_rate >= 0)
|
||||
params->max_eager_freeze_failure_rate =
|
||||
((StdRdOptions *) rel->rd_options)->vacuum_max_eager_freeze_failure_rate;
|
||||
|
||||
/*
|
||||
* Set truncate option based on truncate reloption if it wasn't specified
|
||||
* in VACUUM command, or when running in an autovacuum worker
|
||||
|
Reference in New Issue
Block a user