mirror of
https://github.com/postgres/postgres.git
synced 2025-07-03 20:02:46 +03:00
Add log_min_autovacuum_duration per-table option
This is useful to control autovacuum log volume, for situations where monitoring only a set of tables is necessary. Author: Michael Paquier Reviewed by: A team led by Naoya Anzai (also including Akira Kurosawa, Taiki Kondo, Huong Dangminh), Fujii Masao.
This commit is contained in:
@ -881,9 +881,9 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
|
|||||||
<literal>toast.</literal>, which can be used to control the behavior of the
|
<literal>toast.</literal>, which can be used to control the behavior of the
|
||||||
table's secondary <acronym>TOAST</> table, if any
|
table's secondary <acronym>TOAST</> table, if any
|
||||||
(see <xref linkend="storage-toast"> for more information about TOAST).
|
(see <xref linkend="storage-toast"> for more information about TOAST).
|
||||||
Note that the TOAST table inherits the
|
Note that the TOAST table uses the parameter values defined for
|
||||||
<literal>autovacuum_*</literal> values from its parent table, if there are
|
the main table, for each parameter applicable to TOAST tables and
|
||||||
no <literal>toast.autovacuum_*</literal> settings set.
|
for which no value is set in the TOAST table itself.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<variablelist>
|
<variablelist>
|
||||||
@ -1060,6 +1060,15 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><literal>log_autovacuum_min_duration</literal>, <literal>toast.log_autovacuum_min_duration</literal> (<type>integer</type>)</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Custom <xref linkend="guc-log-autovacuum-min-duration"> parameter.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><literal>user_catalog_table</literal> (<type>boolean</type>)</term>
|
<term><literal>user_catalog_table</literal> (<type>boolean</type>)</term>
|
||||||
<listitem>
|
<listitem>
|
||||||
@ -1067,6 +1076,7 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
|
|||||||
Declare a table as an additional catalog table, e.g. for the purpose of
|
Declare a table as an additional catalog table, e.g. for the purpose of
|
||||||
logical replication. See
|
logical replication. See
|
||||||
<xref linkend="logicaldecoding-capabilities"> for details.
|
<xref linkend="logicaldecoding-capabilities"> for details.
|
||||||
|
This parameter cannot be set for TOAST tables.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
@ -209,6 +209,14 @@ static relopt_int intRelOpts[] =
|
|||||||
RELOPT_KIND_HEAP | RELOPT_KIND_TOAST
|
RELOPT_KIND_HEAP | RELOPT_KIND_TOAST
|
||||||
}, -1, 0, 2000000000
|
}, -1, 0, 2000000000
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
{
|
||||||
|
"log_autovacuum_min_duration",
|
||||||
|
"Sets the minimum execution time above which autovacuum actions will be logged",
|
||||||
|
RELOPT_KIND_HEAP | RELOPT_KIND_TOAST
|
||||||
|
},
|
||||||
|
-1, -1, INT_MAX
|
||||||
|
},
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
"pages_per_range",
|
"pages_per_range",
|
||||||
@ -1210,6 +1218,8 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
|
|||||||
offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, multixact_freeze_max_age)},
|
offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, multixact_freeze_max_age)},
|
||||||
{"autovacuum_multixact_freeze_table_age", RELOPT_TYPE_INT,
|
{"autovacuum_multixact_freeze_table_age", RELOPT_TYPE_INT,
|
||||||
offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, multixact_freeze_table_age)},
|
offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, multixact_freeze_table_age)},
|
||||||
|
{"log_autovacuum_min_duration", RELOPT_TYPE_INT,
|
||||||
|
offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, log_min_duration)},
|
||||||
{"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL,
|
{"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL,
|
||||||
offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, vacuum_scale_factor)},
|
offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, vacuum_scale_factor)},
|
||||||
{"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL,
|
{"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL,
|
||||||
|
@ -85,7 +85,8 @@ static MemoryContext anl_context = NULL;
|
|||||||
static BufferAccessStrategy vac_strategy;
|
static BufferAccessStrategy vac_strategy;
|
||||||
|
|
||||||
|
|
||||||
static void do_analyze_rel(Relation onerel, int options, List *va_cols,
|
static void do_analyze_rel(Relation onerel, int options,
|
||||||
|
VacuumParams *params, List *va_cols,
|
||||||
AcquireSampleRowsFunc acquirefunc, BlockNumber relpages,
|
AcquireSampleRowsFunc acquirefunc, BlockNumber relpages,
|
||||||
bool inh, bool in_outer_xact, int elevel);
|
bool inh, bool in_outer_xact, int elevel);
|
||||||
static void BlockSampler_Init(BlockSampler bs, BlockNumber nblocks,
|
static void BlockSampler_Init(BlockSampler bs, BlockNumber nblocks,
|
||||||
@ -115,8 +116,9 @@ static Datum ind_fetch_func(VacAttrStatsP stats, int rownum, bool *isNull);
|
|||||||
* analyze_rel() -- analyze one relation
|
* analyze_rel() -- analyze one relation
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
analyze_rel(Oid relid, RangeVar *relation, int options, List *va_cols,
|
analyze_rel(Oid relid, RangeVar *relation, int options,
|
||||||
bool in_outer_xact, BufferAccessStrategy bstrategy)
|
VacuumParams *params, List *va_cols, bool in_outer_xact,
|
||||||
|
BufferAccessStrategy bstrategy)
|
||||||
{
|
{
|
||||||
Relation onerel;
|
Relation onerel;
|
||||||
int elevel;
|
int elevel;
|
||||||
@ -151,7 +153,7 @@ analyze_rel(Oid relid, RangeVar *relation, int options, List *va_cols,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
onerel = NULL;
|
onerel = NULL;
|
||||||
if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0)
|
if (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
|
||||||
ereport(LOG,
|
ereport(LOG,
|
||||||
(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
|
(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
|
||||||
errmsg("skipping analyze of \"%s\" --- lock not available",
|
errmsg("skipping analyze of \"%s\" --- lock not available",
|
||||||
@ -266,14 +268,14 @@ analyze_rel(Oid relid, RangeVar *relation, int options, List *va_cols,
|
|||||||
/*
|
/*
|
||||||
* Do the normal non-recursive ANALYZE.
|
* Do the normal non-recursive ANALYZE.
|
||||||
*/
|
*/
|
||||||
do_analyze_rel(onerel, options, va_cols, acquirefunc, relpages,
|
do_analyze_rel(onerel, options, params, va_cols, acquirefunc, relpages,
|
||||||
false, in_outer_xact, elevel);
|
false, in_outer_xact, elevel);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there are child tables, do recursive ANALYZE.
|
* If there are child tables, do recursive ANALYZE.
|
||||||
*/
|
*/
|
||||||
if (onerel->rd_rel->relhassubclass)
|
if (onerel->rd_rel->relhassubclass)
|
||||||
do_analyze_rel(onerel, options, va_cols, acquirefunc, relpages,
|
do_analyze_rel(onerel, options, params, va_cols, acquirefunc, relpages,
|
||||||
true, in_outer_xact, elevel);
|
true, in_outer_xact, elevel);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -301,9 +303,10 @@ analyze_rel(Oid relid, RangeVar *relation, int options, List *va_cols,
|
|||||||
* appropriate acquirefunc for each child table.
|
* appropriate acquirefunc for each child table.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
do_analyze_rel(Relation onerel, int options, List *va_cols,
|
do_analyze_rel(Relation onerel, int options, VacuumParams *params,
|
||||||
AcquireSampleRowsFunc acquirefunc, BlockNumber relpages,
|
List *va_cols, AcquireSampleRowsFunc acquirefunc,
|
||||||
bool inh, bool in_outer_xact, int elevel)
|
BlockNumber relpages, bool inh, bool in_outer_xact,
|
||||||
|
int elevel)
|
||||||
{
|
{
|
||||||
int attr_cnt,
|
int attr_cnt,
|
||||||
tcnt,
|
tcnt,
|
||||||
@ -359,10 +362,10 @@ do_analyze_rel(Relation onerel, int options, List *va_cols,
|
|||||||
save_nestlevel = NewGUCNestLevel();
|
save_nestlevel = NewGUCNestLevel();
|
||||||
|
|
||||||
/* measure elapsed time iff autovacuum logging requires it */
|
/* measure elapsed time iff autovacuum logging requires it */
|
||||||
if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0)
|
if (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
|
||||||
{
|
{
|
||||||
pg_rusage_init(&ru0);
|
pg_rusage_init(&ru0);
|
||||||
if (Log_autovacuum_min_duration > 0)
|
if (params->log_min_duration > 0)
|
||||||
starttime = GetCurrentTimestamp();
|
starttime = GetCurrentTimestamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -647,11 +650,11 @@ do_analyze_rel(Relation onerel, int options, List *va_cols,
|
|||||||
vac_close_indexes(nindexes, Irel, NoLock);
|
vac_close_indexes(nindexes, Irel, NoLock);
|
||||||
|
|
||||||
/* Log the action if appropriate */
|
/* Log the action if appropriate */
|
||||||
if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0)
|
if (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
|
||||||
{
|
{
|
||||||
if (Log_autovacuum_min_duration == 0 ||
|
if (params->log_min_duration == 0 ||
|
||||||
TimestampDifferenceExceeds(starttime, GetCurrentTimestamp(),
|
TimestampDifferenceExceeds(starttime, GetCurrentTimestamp(),
|
||||||
Log_autovacuum_min_duration))
|
params->log_min_duration))
|
||||||
ereport(LOG,
|
ereport(LOG,
|
||||||
(errmsg("automatic analyze of table \"%s.%s.%s\" system usage: %s",
|
(errmsg("automatic analyze of table \"%s.%s.%s\" system usage: %s",
|
||||||
get_database_name(MyDatabaseId),
|
get_database_name(MyDatabaseId),
|
||||||
|
@ -114,6 +114,9 @@ ExecVacuum(VacuumStmt *vacstmt, bool isTopLevel)
|
|||||||
/* user-invoked vacuum is never "for wraparound" */
|
/* user-invoked vacuum is never "for wraparound" */
|
||||||
params.is_wraparound = false;
|
params.is_wraparound = false;
|
||||||
|
|
||||||
|
/* user-invoked vacuum never uses this parameter */
|
||||||
|
params.log_min_duration = -1;
|
||||||
|
|
||||||
/* Now go through the common routine */
|
/* Now go through the common routine */
|
||||||
vacuum(vacstmt->options, vacstmt->relation, InvalidOid, ¶ms,
|
vacuum(vacstmt->options, vacstmt->relation, InvalidOid, ¶ms,
|
||||||
vacstmt->va_cols, NULL, isTopLevel);
|
vacstmt->va_cols, NULL, isTopLevel);
|
||||||
@ -304,7 +307,7 @@ vacuum(int options, RangeVar *relation, Oid relid, VacuumParams *params,
|
|||||||
PushActiveSnapshot(GetTransactionSnapshot());
|
PushActiveSnapshot(GetTransactionSnapshot());
|
||||||
}
|
}
|
||||||
|
|
||||||
analyze_rel(relid, relation, options,
|
analyze_rel(relid, relation, options, params,
|
||||||
va_cols, in_outer_xact, vac_strategy);
|
va_cols, in_outer_xact, vac_strategy);
|
||||||
|
|
||||||
if (use_own_xacts)
|
if (use_own_xacts)
|
||||||
@ -1233,7 +1236,7 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
onerel = NULL;
|
onerel = NULL;
|
||||||
if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0)
|
if (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
|
||||||
ereport(LOG,
|
ereport(LOG,
|
||||||
(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
|
(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
|
||||||
errmsg("skipping vacuum of \"%s\" --- lock not available",
|
errmsg("skipping vacuum of \"%s\" --- lock not available",
|
||||||
|
@ -196,7 +196,7 @@ lazy_vacuum_rel(Relation onerel, int options, VacuumParams *params,
|
|||||||
Assert(params != NULL);
|
Assert(params != NULL);
|
||||||
|
|
||||||
/* measure elapsed time iff autovacuum logging requires it */
|
/* measure elapsed time iff autovacuum logging requires it */
|
||||||
if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0)
|
if (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
|
||||||
{
|
{
|
||||||
pg_rusage_init(&ru0);
|
pg_rusage_init(&ru0);
|
||||||
starttime = GetCurrentTimestamp();
|
starttime = GetCurrentTimestamp();
|
||||||
@ -328,13 +328,13 @@ lazy_vacuum_rel(Relation onerel, int options, VacuumParams *params,
|
|||||||
vacrelstats->new_dead_tuples);
|
vacrelstats->new_dead_tuples);
|
||||||
|
|
||||||
/* and log the action if appropriate */
|
/* and log the action if appropriate */
|
||||||
if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0)
|
if (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
|
||||||
{
|
{
|
||||||
TimestampTz endtime = GetCurrentTimestamp();
|
TimestampTz endtime = GetCurrentTimestamp();
|
||||||
|
|
||||||
if (Log_autovacuum_min_duration == 0 ||
|
if (params->log_min_duration == 0 ||
|
||||||
TimestampDifferenceExceeds(starttime, endtime,
|
TimestampDifferenceExceeds(starttime, endtime,
|
||||||
Log_autovacuum_min_duration))
|
params->log_min_duration))
|
||||||
{
|
{
|
||||||
StringInfoData buf;
|
StringInfoData buf;
|
||||||
TimestampDifference(starttime, endtime, &secs, &usecs);
|
TimestampDifference(starttime, endtime, &secs, &usecs);
|
||||||
|
@ -2493,6 +2493,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
|
|||||||
int multixact_freeze_table_age;
|
int multixact_freeze_table_age;
|
||||||
int vac_cost_limit;
|
int vac_cost_limit;
|
||||||
int vac_cost_delay;
|
int vac_cost_delay;
|
||||||
|
int log_min_duration;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculate the vacuum cost parameters and the freeze ages. If there
|
* Calculate the vacuum cost parameters and the freeze ages. If there
|
||||||
@ -2515,6 +2516,11 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
|
|||||||
? autovacuum_vac_cost_limit
|
? autovacuum_vac_cost_limit
|
||||||
: VacuumCostLimit;
|
: VacuumCostLimit;
|
||||||
|
|
||||||
|
/* -1 in autovac setting means use log_autovacuum_min_duration */
|
||||||
|
log_min_duration = (avopts && avopts->log_min_duration >= 0)
|
||||||
|
? avopts->log_min_duration
|
||||||
|
: Log_autovacuum_min_duration;
|
||||||
|
|
||||||
/* these do not have autovacuum-specific settings */
|
/* these do not have autovacuum-specific settings */
|
||||||
freeze_min_age = (avopts && avopts->freeze_min_age >= 0)
|
freeze_min_age = (avopts && avopts->freeze_min_age >= 0)
|
||||||
? avopts->freeze_min_age
|
? avopts->freeze_min_age
|
||||||
@ -2545,6 +2551,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
|
|||||||
tab->at_params.multixact_freeze_min_age = multixact_freeze_min_age;
|
tab->at_params.multixact_freeze_min_age = multixact_freeze_min_age;
|
||||||
tab->at_params.multixact_freeze_table_age = multixact_freeze_table_age;
|
tab->at_params.multixact_freeze_table_age = multixact_freeze_table_age;
|
||||||
tab->at_params.is_wraparound = wraparound;
|
tab->at_params.is_wraparound = wraparound;
|
||||||
|
tab->at_params.log_min_duration = log_min_duration;
|
||||||
tab->at_vacuum_cost_limit = vac_cost_limit;
|
tab->at_vacuum_cost_limit = vac_cost_limit;
|
||||||
tab->at_vacuum_cost_delay = vac_cost_delay;
|
tab->at_vacuum_cost_delay = vac_cost_delay;
|
||||||
tab->at_relname = NULL;
|
tab->at_relname = NULL;
|
||||||
|
@ -1788,6 +1788,7 @@ psql_completion(const char *text, int start, int end)
|
|||||||
"autovacuum_vacuum_scale_factor",
|
"autovacuum_vacuum_scale_factor",
|
||||||
"autovacuum_vacuum_threshold",
|
"autovacuum_vacuum_threshold",
|
||||||
"fillfactor",
|
"fillfactor",
|
||||||
|
"log_autovacuum_min_duration",
|
||||||
"toast.autovacuum_enabled",
|
"toast.autovacuum_enabled",
|
||||||
"toast.autovacuum_freeze_max_age",
|
"toast.autovacuum_freeze_max_age",
|
||||||
"toast.autovacuum_freeze_min_age",
|
"toast.autovacuum_freeze_min_age",
|
||||||
@ -1799,6 +1800,7 @@ psql_completion(const char *text, int start, int end)
|
|||||||
"toast.autovacuum_vacuum_cost_limit",
|
"toast.autovacuum_vacuum_cost_limit",
|
||||||
"toast.autovacuum_vacuum_scale_factor",
|
"toast.autovacuum_vacuum_scale_factor",
|
||||||
"toast.autovacuum_vacuum_threshold",
|
"toast.autovacuum_vacuum_threshold",
|
||||||
|
"toast.log_autovacuum_min_duration",
|
||||||
"user_catalog_table",
|
"user_catalog_table",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
@ -142,6 +142,9 @@ typedef struct VacuumParams
|
|||||||
int multixact_freeze_table_age; /* multixact age at which to
|
int multixact_freeze_table_age; /* multixact age at which to
|
||||||
* scan whole table */
|
* scan whole table */
|
||||||
bool is_wraparound; /* force a for-wraparound vacuum */
|
bool is_wraparound; /* force a for-wraparound vacuum */
|
||||||
|
int log_min_duration; /* minimum execution threshold in ms at
|
||||||
|
* which verbose logs are activated,
|
||||||
|
* -1 to use default */
|
||||||
} VacuumParams;
|
} VacuumParams;
|
||||||
|
|
||||||
/* GUC parameters */
|
/* GUC parameters */
|
||||||
@ -191,7 +194,7 @@ extern void lazy_vacuum_rel(Relation onerel, int options,
|
|||||||
|
|
||||||
/* in commands/analyze.c */
|
/* in commands/analyze.c */
|
||||||
extern void analyze_rel(Oid relid, RangeVar *relation, int options,
|
extern void analyze_rel(Oid relid, RangeVar *relation, int options,
|
||||||
List *va_cols, bool in_outer_xact,
|
VacuumParams *params, List *va_cols, bool in_outer_xact,
|
||||||
BufferAccessStrategy bstrategy);
|
BufferAccessStrategy bstrategy);
|
||||||
extern bool std_typanalyze(VacAttrStats *stats);
|
extern bool std_typanalyze(VacAttrStats *stats);
|
||||||
extern double anl_random_fract(void);
|
extern double anl_random_fract(void);
|
||||||
|
@ -209,6 +209,7 @@ typedef struct AutoVacOpts
|
|||||||
int multixact_freeze_min_age;
|
int multixact_freeze_min_age;
|
||||||
int multixact_freeze_max_age;
|
int multixact_freeze_max_age;
|
||||||
int multixact_freeze_table_age;
|
int multixact_freeze_table_age;
|
||||||
|
int log_min_duration;
|
||||||
float8 vacuum_scale_factor;
|
float8 vacuum_scale_factor;
|
||||||
float8 analyze_scale_factor;
|
float8 analyze_scale_factor;
|
||||||
} AutoVacOpts;
|
} AutoVacOpts;
|
||||||
|
Reference in New Issue
Block a user