From 399192400ab1e8f8bb13b4cbb17141beba503339 Mon Sep 17 00:00:00 2001 From: Melanie Plageman Date: Wed, 5 Apr 2023 17:22:02 -0400 Subject: [PATCH v13 2/3] Add VACUUM BUFFER_USAGE_LIMIT option and GUC Add GUC, vacuum_buffer_usage_limit, and VACUUM option, BUFFER_USAGE_LIMIT, through which the user can specify the maximum size to use for buffers for VACUUM, ANALYZE, and autovacuum. The size is converted into a number of shared buffers which are tracked in a BufferAccessStrategyData object. The explicit VACUUM option, when specified, overrides the GUC value, unless it is specified as -1. Reviewed-by: David Rowley Reviewed-by: Andres Freund Reviewed-by: Justin Pryzby Discussion: https://www.postgresql.org/message-id/flat/20230111182720.ejifsclfwymw2reb%40awork3.anarazel.de --- doc/src/sgml/config.sgml | 30 ++++++ doc/src/sgml/ref/analyze.sgml | 18 ++++ doc/src/sgml/ref/vacuum.sgml | 22 +++++ src/backend/commands/vacuum.c | 95 ++++++++++++++++++- src/backend/commands/vacuumparallel.c | 14 ++- src/backend/postmaster/autovacuum.c | 13 ++- src/backend/storage/buffer/README | 4 + src/backend/storage/buffer/freelist.c | 48 ++++++++-- src/backend/utils/init/globals.c | 5 +- src/backend/utils/misc/guc_tables.c | 11 +++ src/backend/utils/misc/postgresql.conf.sample | 4 + src/bin/psql/tab-complete.c | 4 +- src/include/miscadmin.h | 13 +++ src/include/storage/bufmgr.h | 6 ++ src/include/utils/guc_hooks.h | 3 + src/test/regress/expected/vacuum.out | 4 + src/test/regress/sql/vacuum.sql | 3 + 17 files changed, 283 insertions(+), 14 deletions(-) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index bcc49aec45..1d75ec62df 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -2001,6 +2001,36 @@ include_dir 'conf.d' + + + vacuum_buffer_usage_limit (integer) + + vacuum_buffer_usage_limit configuration parameter + + + + + Specifies the size of shared_buffers to be reused + for each backend participating in a given invocation of + VACUUM or ANALYZE or in + autovacuum. This size is converted to the number of shared buffers + which will be reused as part of a + Buffer Access Strategy. + A setting of 0 will allow the operation to use any + number of shared_buffers, whereas + -1 will set the size to a default of 256 KB. + The maximum size is 16 GB and the minimum size is 128 KB. + If the specified size would exceed 1/8 the size of + shared_buffers, it is silently capped. + The default value is -1. If this value is specified + without units, it is taken as kilobytes. This parameter can be set at + any time. It can be overridden for + and + when passing the option. + + + + logical_decoding_work_mem (integer) diff --git a/doc/src/sgml/ref/analyze.sgml b/doc/src/sgml/ref/analyze.sgml index 2f94e89cb0..16cde8668e 100644 --- a/doc/src/sgml/ref/analyze.sgml +++ b/doc/src/sgml/ref/analyze.sgml @@ -28,6 +28,7 @@ ANALYZE [ VERBOSE ] [ table_and_columnsboolean ] SKIP_LOCKED [ boolean ] + BUFFER_USAGE_LIMIT [ string ] and table_and_columns is: @@ -95,6 +96,23 @@ ANALYZE [ VERBOSE ] [ table_and_columns + + BUFFER_USAGE_LIMIT + + + Specifies the + Buffer Access Strategy + ring buffer size for ANALYZE. This size is used to + calculate the number of shared buffers which will be reused as part of + this strategy. 0 disables use of a + Buffer Access Strategy. -1 + indicates that ANALYZE should fall back to the value + specified by . + + + + + boolean diff --git a/doc/src/sgml/ref/vacuum.sgml b/doc/src/sgml/ref/vacuum.sgml index b6d30b5764..c1ddf88cf8 100644 --- a/doc/src/sgml/ref/vacuum.sgml +++ b/doc/src/sgml/ref/vacuum.sgml @@ -39,6 +39,7 @@ VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] [ ANALYZE ] [ integer SKIP_DATABASE_STATS [ boolean ] ONLY_DATABASE_STATS [ boolean ] + BUFFER_USAGE_LIMIT [ string ] and table_and_columns is: @@ -345,6 +346,27 @@ VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] [ ANALYZE ] [ Buffer Access Strategy + ring buffer size for VACUUM. This size is used to + calculate the number of shared buffers which will be reused as part of + this strategy. 0 disables use of a + Buffer Access Strategy. -1 + indicates that VACUUM should fall back to the value + specified by . + This option can't be used with the option or + option. If + is also specified, the + value is used for both the vacuum + and analyze stages. + + + + boolean diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index cde5ee41a5..5427e2dedc 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -56,6 +56,7 @@ #include "utils/acl.h" #include "utils/fmgroids.h" #include "utils/guc.h" +#include "utils/guc_hooks.h" #include "utils/memutils.h" #include "utils/pg_rusage.h" #include "utils/snapmgr.h" @@ -95,6 +96,29 @@ static VacOptValue get_vacoptval_from_boolean(DefElem *def); static bool vac_tid_reaped(ItemPointer itemptr, void *state); static int vac_cmp_itemptr(const void *left, const void *right); +/* + * GUC check function to ensure GUC value specified is within the allowable + * range. This should match the checking in ExecVacuum(). + */ +bool +check_vacuum_buffer_usage_limit(int *newval, void **extra, + GucSource source) +{ + /* Allow specifying the default or disabling Buffer Access Strategy */ + if (*newval == -1 || *newval == 0) + return true; + + /* Value upper and lower hard limits are inclusive */ + if (*newval >= MIN_BAS_VAC_RING_SIZE_KB && *newval <= MAX_BAS_VAC_RING_SIZE_KB) + return true; + + /* Value does not fall within any allowable range */ + GUC_check_errdetail("\"vacuum_buffer_usage_limit\" must be 0 or between %d KB and %d KB", + MIN_BAS_VAC_RING_SIZE_KB, MAX_BAS_VAC_RING_SIZE_KB); + + return false; +} + /* * Primary entry point for manual VACUUM and ANALYZE commands * @@ -114,6 +138,8 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel) bool disable_page_skipping = false; bool process_main = true; bool process_toast = true; + /* by default use buffer access strategy with default size */ + int ring_size = -1; bool skip_database_stats = false; bool only_database_stats = false; MemoryContext vac_context; @@ -139,6 +165,46 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel) verbose = defGetBoolean(opt); else if (strcmp(opt->defname, "skip_locked") == 0) skip_locked = defGetBoolean(opt); + else if (strcmp(opt->defname, "buffer_usage_limit") == 0) + { + const char *hintmsg; + int result; + char *vac_buffer_size; + + if (opt->arg == NULL) + { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("buffer_usage_limit option requires a valid value"), + parser_errposition(pstate, opt->location))); + } + + vac_buffer_size = defGetString(opt); + + if (!parse_int(vac_buffer_size, &result, GUC_UNIT_KB, &hintmsg)) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("value: \"%s\": is invalid for buffer_usage_limit", + vac_buffer_size), + hintmsg ? errhint("%s", _(hintmsg)) : 0)); + } + + /* + * Check that the specified size falls within the hard upper and + * lower limits if it is not -1 or 0. + */ + if (result != -1 && result != 0 && + (result < MIN_BAS_VAC_RING_SIZE_KB || result > MAX_BAS_VAC_RING_SIZE_KB)) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("buffer_usage_limit for a vacuum must be 0 or between %d KB and %d KB", + MIN_BAS_VAC_RING_SIZE_KB, MAX_BAS_VAC_RING_SIZE_KB))); + } + + ring_size = result; + } else if (!vacstmt->is_vacuumcmd) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), @@ -243,6 +309,16 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel) (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("VACUUM FULL cannot be performed in parallel"))); + if ((params.options & VACOPT_FULL) && ring_size > -1) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("BUFFER_USAGE_LIMIT cannot be specified for VACUUM FULL"))); + + if ((params.options & VACOPT_ONLY_DATABASE_STATS) && ring_size > -1) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("BUFFER_USAGE_LIMIT cannot be specified for VACUUM ONLY_DATABASE_STATS"))); + /* * Make sure VACOPT_ANALYZE is specified if any column lists are present. */ @@ -362,7 +438,24 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel) MemoryContext old_context = MemoryContextSwitchTo(vac_context); - bstrategy = GetAccessStrategy(BAS_VACUUM); + Assert(ring_size >= -1); + + /* + * If explicit VACUUM or ANALYZE specified a non-default + * BUFFER_USAGE_LIMIT, that overrides the value of GUC + * VacuumBufferUsageLimit. If VacuumBufferUsageLimit is set to + * something other than the default, use its value. Otherwise, use the + * default sizes for a Buffer Access Strategy. Note that autovacuum + * will have set VacuumParams->ring_size to the value it derived from + * VacuumBufferUsageLimit. + */ + if (ring_size > -1) + bstrategy = GetAccessStrategyWithSize(BAS_VACUUM, ring_size); + else if (VacuumBufferUsageLimit > -1) + bstrategy = GetAccessStrategyWithSize(BAS_VACUUM, VacuumBufferUsageLimit); + else + bstrategy = GetAccessStrategy(BAS_VACUUM); + MemoryContextSwitchTo(old_context); } diff --git a/src/backend/commands/vacuumparallel.c b/src/backend/commands/vacuumparallel.c index 563117a8f6..614a35779a 100644 --- a/src/backend/commands/vacuumparallel.c +++ b/src/backend/commands/vacuumparallel.c @@ -87,6 +87,12 @@ typedef struct PVShared */ int maintenance_work_mem_worker; + /* + * The number of buffers each worker's Buffer Access Strategy ring should + * contain. + */ + int ring_nbuffers; + /* * Shared vacuum cost balance. During parallel vacuum, * VacuumSharedCostBalance points to this value and it accumulates the @@ -365,6 +371,9 @@ parallel_vacuum_init(Relation rel, Relation *indrels, int nindexes, maintenance_work_mem / Min(parallel_workers, nindexes_mwm) : maintenance_work_mem; + /* Use the same buffer size for all workers */ + shared->ring_nbuffers = StrategyGetBufferCount(bstrategy); + pg_atomic_init_u32(&(shared->cost_balance), 0); pg_atomic_init_u32(&(shared->active_nworkers), 0); pg_atomic_init_u32(&(shared->idx), 0); @@ -1018,8 +1027,9 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc) pvs.indname = NULL; pvs.status = PARALLEL_INDVAC_STATUS_INITIAL; - /* Each parallel VACUUM worker gets its own access strategy */ - pvs.bstrategy = GetAccessStrategy(BAS_VACUUM); + /* Each parallel VACUUM worker gets its own access strategy. */ + pvs.bstrategy = GetAccessStrategyWithSize(BAS_VACUUM, + shared->ring_nbuffers * (BLCKSZ / 1024)); /* Setup error traceback support for ereport() */ errcallback.callback = parallel_vacuum_error_callback; diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index d2b6f41ead..421adc7ad7 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -2290,9 +2290,18 @@ do_autovacuum(void) /* * Create a buffer access strategy object for VACUUM to use. We want to * use the same one across all the vacuum operations we perform, since the - * point is for VACUUM not to blow out the shared cache. + * point is for VACUUM not to blow out the shared cache. If we later enter + * failsafe mode, we will cease use of the BufferAccessStrategy. Either + * way, we clean up the BufferAccessStrategy object at the end of this + * function. + * + * XXX: In the future we may want to react to changes in + * VacuumBufferUsageLimit while vacuuming. */ - bstrategy = GetAccessStrategy(BAS_VACUUM); + if (VacuumBufferUsageLimit > -1) + bstrategy = GetAccessStrategyWithSize(BAS_VACUUM, VacuumBufferUsageLimit); + else + bstrategy = GetAccessStrategy(BAS_VACUUM); /* * create a memory context to act as fake PortalContext, so that the diff --git a/src/backend/storage/buffer/README b/src/backend/storage/buffer/README index a775276ff2..d7c9d99af2 100644 --- a/src/backend/storage/buffer/README +++ b/src/backend/storage/buffer/README @@ -236,6 +236,10 @@ buffers were sent to the freelist, which was effectively a buffer ring of 1 buffer, resulting in excessive WAL flushing. Allowing VACUUM to update 256KB between WAL flushes should be more efficient. +In v16, the 256KB ring was made configurable by way of the +vacuum_buffer_usage_limit GUC and the BUFFER_USAGE_LIMIT option to VACUUM and +ANALYZE. + Bulk writes work similarly to VACUUM. Currently this applies only to COPY IN and CREATE TABLE AS SELECT. (Might it be interesting to make seqscan UPDATE and DELETE use the bulkwrite strategy?) For bulk writes diff --git a/src/backend/storage/buffer/freelist.c b/src/backend/storage/buffer/freelist.c index f122709fbe..0c1ce8b93f 100644 --- a/src/backend/storage/buffer/freelist.c +++ b/src/backend/storage/buffer/freelist.c @@ -540,8 +540,7 @@ StrategyInitialize(bool init) BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype) { - BufferAccessStrategy strategy; - int nbuffers; + int ring_size_kb; /* * Select ring size to use. See buffer/README for rationales. @@ -556,13 +555,13 @@ GetAccessStrategy(BufferAccessStrategyType btype) return NULL; case BAS_BULKREAD: - nbuffers = 256 * 1024 / BLCKSZ; + ring_size_kb = 256; break; case BAS_BULKWRITE: - nbuffers = 16 * 1024 * 1024 / BLCKSZ; + ring_size_kb = 16 * 1024; break; case BAS_VACUUM: - nbuffers = 256 * 1024 / BLCKSZ; + ring_size_kb = 256; break; default: @@ -571,8 +570,36 @@ GetAccessStrategy(BufferAccessStrategyType btype) return NULL; /* keep compiler quiet */ } + return GetAccessStrategyWithSize(btype, ring_size_kb); +} + +/* + * GetAccessStrategyWithSize -- create a BufferAccessStrategy object with a + * number of buffers equivalent to the passed in size + */ +BufferAccessStrategy +GetAccessStrategyWithSize(BufferAccessStrategyType btype, int ring_size_kb) +{ + int blcksz_kb = BLCKSZ / 1024; + int nbuffers; + int sb_limit_kb; + BufferAccessStrategy strategy; + + /* Default nbuffers should have resulted in calling GetAccessStrategy() */ + Assert(ring_size_kb >= 0); + + if (ring_size_kb == 0) + return NULL; + + Assert(blcksz_kb > 0); + /* Make sure ring isn't an undue fraction of shared buffers */ - nbuffers = Min(NBuffers / 8, nbuffers); + sb_limit_kb = NBuffers / 8 * blcksz_kb; + ring_size_kb = Min(sb_limit_kb, ring_size_kb); + + nbuffers = ring_size_kb / blcksz_kb; + + Assert(nbuffers > 0); /* Allocate the object and initialize all elements to zeroes */ strategy = (BufferAccessStrategy) @@ -586,6 +613,15 @@ GetAccessStrategy(BufferAccessStrategyType btype) return strategy; } +/* + * StrategyGetBufferCount -- an accessor for the number of buffers in the ring + */ +int +StrategyGetBufferCount(BufferAccessStrategy strategy) +{ + return strategy->nbuffers; +} + /* * FreeAccessStrategy -- release a BufferAccessStrategy object * diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c index 1b1d814254..059a097bef 100644 --- a/src/backend/utils/init/globals.c +++ b/src/backend/utils/init/globals.c @@ -139,7 +139,10 @@ int max_worker_processes = 8; int max_parallel_workers = 8; int MaxBackends = 0; -int VacuumCostPageHit = 1; /* GUC parameters for vacuum */ +/* GUC parameters for vacuum */ +int VacuumBufferUsageLimit = -1; + +int VacuumCostPageHit = 1; int VacuumCostPageMiss = 2; int VacuumCostPageDirty = 20; int VacuumCostLimit = 200; diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c index 8062589efd..5bad2b540f 100644 --- a/src/backend/utils/misc/guc_tables.c +++ b/src/backend/utils/misc/guc_tables.c @@ -2224,6 +2224,17 @@ struct config_int ConfigureNamesInt[] = NULL, NULL, NULL }, + { + {"vacuum_buffer_usage_limit", PGC_USERSET, RESOURCES_MEM, + gettext_noop("Sets the buffer pool size for VACUUM, ANALYZE, and autovacuum."), + NULL, + GUC_UNIT_KB + }, + &VacuumBufferUsageLimit, + -1, -1, MAX_BAS_VAC_RING_SIZE_KB, + check_vacuum_buffer_usage_limit, NULL, NULL + }, + { {"shared_memory_size", PGC_INTERNAL, PRESET_OPTIONS, gettext_noop("Shows the size of the server's main shared memory area (rounded up to the nearest MB)."), diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index ee49ca3937..cdbcb95a07 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -157,6 +157,10 @@ # mmap # (change requires restart) #min_dynamic_shared_memory = 0MB # (change requires restart) +#vacuum_buffer_usage_limit = -1 # size of vacuum and analyze buffer access strategy ring. + # -1 to use default, + # 0 to disable vacuum buffer access strategy + # > 0 to specify size. range 128-16777216 # - Disk - diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index e38a49e8bd..6614fd2e62 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -2662,7 +2662,7 @@ psql_completion(const char *text, int start, int end) * one word, so the above test is correct. */ if (ends_with(prev_wd, '(') || ends_with(prev_wd, ',')) - COMPLETE_WITH("VERBOSE", "SKIP_LOCKED"); + COMPLETE_WITH("VERBOSE", "SKIP_LOCKED", "BUFFER_USAGE_LIMIT"); else if (TailMatches("VERBOSE|SKIP_LOCKED")) COMPLETE_WITH("ON", "OFF"); } @@ -4620,7 +4620,7 @@ psql_completion(const char *text, int start, int end) "DISABLE_PAGE_SKIPPING", "SKIP_LOCKED", "INDEX_CLEANUP", "PROCESS_MAIN", "PROCESS_TOAST", "TRUNCATE", "PARALLEL", "SKIP_DATABASE_STATS", - "ONLY_DATABASE_STATS"); + "ONLY_DATABASE_STATS", "BUFFER_USAGE_LIMIT"); else if (TailMatches("FULL|FREEZE|ANALYZE|VERBOSE|DISABLE_PAGE_SKIPPING|SKIP_LOCKED|PROCESS_MAIN|PROCESS_TOAST|TRUNCATE|SKIP_DATABASE_STATS|ONLY_DATABASE_STATS")) COMPLETE_WITH("ON", "OFF"); else if (TailMatches("INDEX_CLEANUP")) diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index 06a86f9ac1..2d550f26e0 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -263,6 +263,19 @@ extern PGDLLIMPORT double hash_mem_multiplier; extern PGDLLIMPORT int maintenance_work_mem; extern PGDLLIMPORT int max_parallel_maintenance_workers; +/* + * Global values used by VACUUM and autovacuum. + */ +extern PGDLLIMPORT int VacuumBufferUsageLimit; + +/* + * Upper and lower hard limits for the Buffer Access Strategy ring size + * specified by the vacuum_buffer_usage_limit GUC and BUFFER_USAGE_LIMIT option + * to VACUUM and ANALYZE. + */ +#define MAX_BAS_VAC_RING_SIZE_KB (16 * 1024 * 1024) +#define MIN_BAS_VAC_RING_SIZE_KB 128 + extern PGDLLIMPORT int VacuumCostPageHit; extern PGDLLIMPORT int VacuumCostPageMiss; extern PGDLLIMPORT int VacuumCostPageDirty; diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h index 788aa279ba..30daa11f7b 100644 --- a/src/include/storage/bufmgr.h +++ b/src/include/storage/bufmgr.h @@ -260,7 +260,13 @@ extern Size BufferShmemSize(void); extern void AtProcExit_LocalBuffers(void); /* in freelist.c */ + extern BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype); +extern BufferAccessStrategy GetAccessStrategyWithSize( + BufferAccessStrategyType btype, + int ring_size_kb); +extern int StrategyGetBufferCount(BufferAccessStrategy strategy); + extern void FreeAccessStrategy(BufferAccessStrategy strategy); diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index aeb3663071..1893292634 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -33,6 +33,9 @@ extern bool check_autovacuum_max_workers(int *newval, void **extra, GucSource source); extern bool check_autovacuum_work_mem(int *newval, void **extra, GucSource source); + +extern bool check_vacuum_buffer_usage_limit(int *newval, void **extra, + GucSource source); extern bool check_backtrace_functions(char **newval, void **extra, GucSource source); extern void assign_backtrace_functions(const char *newval, void *extra); diff --git a/src/test/regress/expected/vacuum.out b/src/test/regress/expected/vacuum.out index e5a312182e..fe675c5a2e 100644 --- a/src/test/regress/expected/vacuum.out +++ b/src/test/regress/expected/vacuum.out @@ -350,6 +350,10 @@ SELECT t.relfilenode = :toast_filenode AS is_same_toast_filenode f (1 row) +-- BUFFER_USAGE_LIMIT integer overflow error +VACUUM (BUFFER_USAGE_LIMIT 10000000000) vac_option_tab; +ERROR: value: "10000000000": is invalid for buffer_usage_limit +HINT: Value exceeds integer range. -- SKIP_DATABASE_STATS option VACUUM (SKIP_DATABASE_STATS) vactst; -- ONLY_DATABASE_STATS option diff --git a/src/test/regress/sql/vacuum.sql b/src/test/regress/sql/vacuum.sql index a1fad43657..fc068b7705 100644 --- a/src/test/regress/sql/vacuum.sql +++ b/src/test/regress/sql/vacuum.sql @@ -272,6 +272,9 @@ SELECT t.relfilenode = :toast_filenode AS is_same_toast_filenode FROM pg_class c, pg_class t WHERE c.reltoastrelid = t.oid AND c.relname = 'vac_option_tab'; +-- BUFFER_USAGE_LIMIT integer overflow error +VACUUM (BUFFER_USAGE_LIMIT 10000000000) vac_option_tab; + -- SKIP_DATABASE_STATS option VACUUM (SKIP_DATABASE_STATS) vactst; -- 2.37.2