diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index aa5b97f..c41514d 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -153,6 +153,9 @@ static int default_freeze_table_age; static int default_multixact_freeze_min_age; static int default_multixact_freeze_table_age; +/* Counter to determine if statistics should be refreshed */ +static bool use_existing_stats = false; + /* Memory context for long-lived data */ static MemoryContext AutovacMemCxt; @@ -2779,6 +2782,35 @@ get_pgstat_tabentry_relid(Oid relid, bool isshared, PgStat_StatDBEntry *shared, return tabentry; } +static void +recheck_relation_needs_vacanalyze(Oid relid, + Form_pg_class classForm, + AutoVacOpts *avopts, + int effective_multixact_freeze_max_age, + bool *dovacuum, + bool *doanalyze, + bool *wraparound) +{ + PgStat_StatTabEntry *tabentry; + PgStat_StatDBEntry *shared; + PgStat_StatDBEntry *dbentry; + + shared = pgstat_fetch_stat_dbentry(InvalidOid); + dbentry = pgstat_fetch_stat_dbentry(MyDatabaseId); + + /* fetch the pgstat table entry */ + tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared, + shared, dbentry); + + relation_needs_vacanalyze(relid, avopts, classForm, tabentry, + effective_multixact_freeze_max_age, + dovacuum, doanalyze, wraparound); + + /* ignore ANALYZE for toast tables */ + if (classForm->relkind == RELKIND_TOASTVALUE) + *doanalyze = false; +} + /* * table_recheck_autovac * @@ -2797,18 +2829,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map, bool dovacuum; bool doanalyze; autovac_table *tab = NULL; - PgStat_StatTabEntry *tabentry; - PgStat_StatDBEntry *shared; - PgStat_StatDBEntry *dbentry; bool wraparound; AutoVacOpts *avopts; - /* use fresh stats */ - autovac_refresh_stats(); - - shared = pgstat_fetch_stat_dbentry(InvalidOid); - dbentry = pgstat_fetch_stat_dbentry(MyDatabaseId); - /* fetch the relation's relcache entry */ classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid)); if (!HeapTupleIsValid(classTup)) @@ -2831,17 +2854,35 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map, avopts = &hentry->ar_reloptions; } - /* fetch the pgstat table entry */ - tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared, - shared, dbentry); + /* + * Before stats refresh, check existing stats for avoiding + * frequent reloading of pgstats. + * In the case of very large numbers of tables, the cost of re-reading + * the stats file can be significant, and the frequent calls to + * autovac_refresh_stats() can make certain autovacuum workers unable to work. + * So if the last time we checked a table that was already vacuumed after + * refres stats, check the current statistics before refreshing it. + */ + if (use_existing_stats) + { + recheck_relation_needs_vacanalyze(relid, classForm, avopts, + effective_multixact_freeze_max_age, + &dovacuum, &doanalyze, &wraparound); - relation_needs_vacanalyze(relid, avopts, classForm, tabentry, - effective_multixact_freeze_max_age, - &dovacuum, &doanalyze, &wraparound); + /* someone has already issued vacuum, so exit quickly */ + if (!doanalyze && !dovacuum) + { + heap_freetuple(classTup); + return NULL; + } + } - /* ignore ANALYZE for toast tables */ - if (classForm->relkind == RELKIND_TOASTVALUE) - doanalyze = false; + /* use fresh stats and recheck again */ + autovac_refresh_stats(); + + recheck_relation_needs_vacanalyze(relid, classForm, avopts, + effective_multixact_freeze_max_age, + &dovacuum, &doanalyze, &wraparound); /* OK, it needs something done */ if (doanalyze || dovacuum) @@ -2929,10 +2970,17 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map, tab->at_dobalance = !(avopts && (avopts->vacuum_cost_limit > 0 || avopts->vacuum_cost_delay > 0)); + + /* We might be better to refresh stats */ + use_existing_stats = false; + } + else + { + /* The relid has already vacuumed, so we might be better to use existing stats */ + use_existing_stats = true; } heap_freetuple(classTup); - return tab; }