Thanks, Justin, for the review. I have applied the changes where still applicable.
On Fri, 2020-03-06 at 10:52 +1300, David Rowley wrote: > On Fri, 6 Mar 2020 at 03:27, Laurenz Albe <laurenz.a...@cybertec.at> wrote: > > On Thu, 2020-03-05 at 19:40 +1300, David Rowley wrote: > > > 1. I'd go for 2 new GUCs and reloptions. > > > autovacuum_vacuum_insert_threshold (you're currently calling this > > > autovacuum_vacuum_insert_limit. I don't see why the word "limit" is > > > relevant here). The other GUC I think should be named > > > autovacuum_vacuum_insert_scale_factor and these should work exactly > > > the same way as autovacuum_vacuum_threshold and > > > autovacuum_vacuum_scale_factor, but be applied in a similar way to the > > > vacuum settings, but only be applied after we've checked to ensure the > > > table is not otherwise eligible to be vacuumed. > > > > I disagree about the scale_factor (and have not added it to the > > updated version of the patch). If we have a scale_factor, then the > > time between successive autovacuum runs would increase as the table > > gets bigger, which defeats the purpose of reducing the impact of each > > autovacuum run. > > My view here is not really to debate what logically makes the most > sense. I don't really think for a minute that the current > auto-vacuums scale_factor and thresholds are perfect for the job. It's > true that the larger a table becomes, the less often it'll be > vacuumed, but these are control knobs that people have become > accustomed to and I don't really think that making an exception for > this is warranted. Perhaps we can zero out the scale factor by > default and set the threshold into the millions of tuples. We can have > people chime in on what they think about that and why once the code is > written and even perhaps committed. Ok, I submit. My main desire was to keep the number of new GUCs as low as reasonably possible, but making the feature tunable along the known and "trusted" lines may be a good thing. The new parameter is called "autovacuum_vacuum_insert_scale_factor". > Lack of a scale_factor does leave people who regularly truncate their > "append-only" tables out in the cold a bit. Perhaps they'd like > index-only scans to kick in soon after they truncate without having to > wait for 10 million tuples, or so. That point I don't see. Truncating a table resets the counters to 0. > > > 10. I'm slightly worried about the case where we don't quite trigger a > > > normal vacuum but trigger a vacuum due to INSERTs then skip cleaning > > > up the indexes but proceed to leave dead index entries causing indexes > > > to become bloated. It does not seem impossible that given the right > > > balance of INSERTs and UPDATE/DELETEs that this could happen every > > > time and the indexes would just become larger and larger. > > > > Perhaps we can take care of the problem by *not* skipping index > > cleanup if "changes_since_analyze" is substantially greater than 0. > > > > What do you think? > > Well, there is code that skips the index scans when there are 0 dead > tuples found in the heap. If the table is truly INSERT-only then it > won't do any harm since we'll skip the index scan anyway. I think > it's less risky to clean the indexes. If we skip that then there will > be a group of people will suffer from index bloat due to this, no > matter if they realise it or not. Oh I didn't know that. In that case it is better to have this vacuum process indexes as well. I have changed the patch so that it freezes tuples, but does not skip index cleanup. Better err on the side of caution. > > Yes, I think that disabling this by default defeats the purpose. > > Perhaps the solution to that is somewhere else then. I can picture > some sort of load average counters for auto-vacuum and spamming the > logs with WARNINGs if we maintain high enough load for long enough, > but we'd likely be better just completely overhauling the vacuum cost > settings to be a percentage of total effort rather than some fixed > speed. That would allow more powerful servers to run vacuum more > quickly and it would also run more quickly during low load periods. > We'd just need to sample now and again how long vacuuming a series of > page takes then sleep for a time based on how long that took. That's > not for this patch though. Right. Updated patch attached. Yours, Laurenz Albe
From f8859e7570caa2df50c5355997f17bd482829218 Mon Sep 17 00:00:00 2001 From: Laurenz Albe <laurenz.a...@cybertec.at> Date: Fri, 6 Mar 2020 15:29:42 +0100 Subject: [PATCH] Autovacuum tables that have received only inserts Add "autovacuum_vacuum_insert_threshold" and "autovacuum_vacuum_insert_scale_factor" GUC and reloption. The default value for the threshold is 10000000. The scale factor defaults to 0, which means that it is effectively disabled, but it offers some flexibility to tune the feature similar to other autovacuum knobs. Any table that has received more inserts since it was last vacuumed (and that is not vacuumed for another reason) will be autovacuumed with aggressive tuple freezing. This avoids the known problem that insert-only tables are never autovacuumed until they need to have their anti-wraparound autovacuum, which then can be massive and disruptive. To track the number of inserts since the last vacuum, introduce a StatTabEntry "inserts_since_vacuum" that gets reset to 0 after a vacuum. This value is available in "pg_stat_*_tables" as "n_ins_since_vacuum". --- doc/src/sgml/config.sgml | 41 ++++++++++++++++ doc/src/sgml/maintenance.sgml | 11 +++++ doc/src/sgml/monitoring.sgml | 5 ++ doc/src/sgml/ref/create_table.sgml | 30 ++++++++++++ src/backend/access/common/reloptions.c | 22 +++++++++ src/backend/catalog/system_views.sql | 1 + src/backend/postmaster/autovacuum.c | 48 ++++++++++++++++--- src/backend/postmaster/pgstat.c | 5 ++ src/backend/utils/adt/pgstatfuncs.c | 16 +++++++ src/backend/utils/misc/guc.c | 20 ++++++++ src/backend/utils/misc/postgresql.conf.sample | 4 ++ src/bin/psql/tab-complete.c | 4 ++ src/include/catalog/pg_proc.dat | 5 ++ src/include/pgstat.h | 1 + src/include/postmaster/autovacuum.h | 2 + src/include/utils/rel.h | 2 + 16 files changed, 211 insertions(+), 6 deletions(-) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index c1128f89ec..0ed1bb9d5e 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -7244,6 +7244,26 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv; </listitem> </varlistentry> + <varlistentry id="guc-autovacuum-vacuum-insert-threshold" xreflabel="autovacuum_vacuum_insert_threshold"> + <term><varname>autovacuum_vacuum_insert_threshold</varname> (<type>integer</type>) + <indexterm> + <primary><varname>autovacuum_vacuum_insert_threshold</varname></primary> + <secondary>configuration parameter</secondary> + </indexterm> + </term> + <listitem> + <para> + Specifies the number of inserted tuples needed to trigger a + <command>VACUUM</command> in any one table. + The default is 10000000 tuples. + This parameter can only be set in the <filename>postgresql.conf</filename> + file or on the server command line; + but the setting can be overridden for individual tables by + changing table storage parameters. + </para> + </listitem> + </varlistentry> + <varlistentry id="guc-autovacuum-analyze-threshold" xreflabel="autovacuum_analyze_threshold"> <term><varname>autovacuum_analyze_threshold</varname> (<type>integer</type>) <indexterm> @@ -7285,6 +7305,27 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv; </listitem> </varlistentry> + <varlistentry id="guc-autovacuum-vacuum-insert-scale-factor" xreflabel="autovacuum_vacuum_insert_scale_factor"> + <term><varname>autovacuum_vacuum_insert_scale_factor</varname> (<type>floating point</type>) + <indexterm> + <primary><varname>autovacuum_vacuum_insert_scale_factor</varname></primary> + <secondary>configuration parameter</secondary> + </indexterm> + </term> + <listitem> + <para> + Specifies a fraction of the table size to add to + <varname>autovacuum_vacuum_insert_threshold</varname> + when deciding whether to trigger a <command>VACUUM</command>. + The default is 0.0, which means that the table size has no effect. + This parameter can only be set in the <filename>postgresql.conf</filename> + file or on the server command line; + but the setting can be overridden for individual tables by + changing table storage parameters. + </para> + </listitem> + </varlistentry> + <varlistentry id="guc-autovacuum-analyze-scale-factor" xreflabel="autovacuum_analyze_scale_factor"> <term><varname>autovacuum_analyze_scale_factor</varname> (<type>floating point</type>) <indexterm> diff --git a/doc/src/sgml/maintenance.sgml b/doc/src/sgml/maintenance.sgml index ec8bdcd7a4..2f9b36120a 100644 --- a/doc/src/sgml/maintenance.sgml +++ b/doc/src/sgml/maintenance.sgml @@ -788,6 +788,17 @@ vacuum threshold = vacuum base threshold + vacuum scale factor * number of tuple since the last vacuum are scanned. </para> + <para> + A threshold similar to the above is calculated from + <xref linkend="guc-autovacuum-vacuum-insert-threshold"/> and + <xref linkend="guc-autovacuum-vacuum-insert-scale-factor"/>. + Tables that have received more inserts than the calculated threshold + since they were last vacuumed (and are not eligible for vacuuming for + other reasons) will be vacuumed to reduce the impact of a future + anti-wraparound vacuum run. + Such a vacuum will aggressively freeze tuples. + </para> + <para> For analyze, a similar condition is used: the threshold, defined as: <programlisting> diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml index 87586a7b06..05fd6260b7 100644 --- a/doc/src/sgml/monitoring.sgml +++ b/doc/src/sgml/monitoring.sgml @@ -2837,6 +2837,11 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i <entry><type>bigint</type></entry> <entry>Estimated number of rows modified since this table was last analyzed</entry> </row> + <row> + <entry><structfield>n_ins_since_vacuum</structfield></entry> + <entry><type>bigint</type></entry> + <entry>Estimated number of rows inserted since this table was last vacuumed</entry> + </row> <row> <entry><structfield>last_vacuum</structfield></entry> <entry><type>timestamp with time zone</type></entry> diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml index 4a2b6f0dae..20acede7e3 100644 --- a/doc/src/sgml/ref/create_table.sgml +++ b/doc/src/sgml/ref/create_table.sgml @@ -1475,6 +1475,36 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM </listitem> </varlistentry> + <varlistentry id="reloption-autovacuum-vacuum-insert-threshold" xreflabel="autovacuum_vacuum_insert_threshold"> + <term><literal>autovacuum_vacuum_insert_threshold</literal>, <literal>toast.autovacuum_vacuum_insert_threshold</literal> (<type>integer</type>) + <indexterm> + <primary><varname>autovacuum_vacuum_insert_threshold</varname></primary> + <secondary>storage parameter</secondary> + </indexterm> + </term> + <listitem> + <para> + Per-table value for <xref linkend="guc-autovacuum-vacuum-insert-threshold"/> + parameter. + </para> + </listitem> + </varlistentry> + + <varlistentry id="reloption-autovacuum-vacuum-insert-scale-factor" xreflabel="autovacuum_vacuum_insert_scale_factor"> + <term><literal>autovacuum_vacuum_insert_scale_factor</literal>, <literal>toast.autovacuum_vacuum_insert_scale_factor</literal> (<type>float4</type>) + <indexterm> + <primary><varname>autovacuum_vacuum_insert_scale_factor</varname> </primary> + <secondary>storage parameter</secondary> + </indexterm> + </term> + <listitem> + <para> + Per-table value for <xref linkend="guc-autovacuum-vacuum-insert-scale-factor"/> + parameter. + </para> + </listitem> + </varlistentry> + <varlistentry id="reloption-autovacuum-analyze-threshold" xreflabel="autovacuum_analyze_threshold"> <term><literal>autovacuum_analyze_threshold</literal> (<type>integer</type>) <indexterm> diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 5325dd3f61..245b0af535 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -233,6 +233,15 @@ static relopt_int intRelOpts[] = }, -1, 0, INT_MAX }, + { + { + "autovacuum_vacuum_insert_threshold", + "Minimum number of tuple inserts prior to vacuum", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + -1, 0, INT_MAX + }, { { "autovacuum_analyze_threshold", @@ -385,6 +394,15 @@ static relopt_real realRelOpts[] = }, -1, 0.0, 100.0 }, + { + { + "autovacuum_vacuum_insert_scale_factor", + "Number of tuple inserts prior to vacuum as a fraction of reltuples", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + -1, 0.0, 100.0 + }, { { "autovacuum_analyze_scale_factor", @@ -1501,6 +1519,8 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, enabled)}, {"autovacuum_vacuum_threshold", RELOPT_TYPE_INT, offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_threshold)}, + {"autovacuum_vacuum_insert_threshold", RELOPT_TYPE_INT, + offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_ins_threshold)}, {"autovacuum_analyze_threshold", RELOPT_TYPE_INT, offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_threshold)}, {"autovacuum_vacuum_cost_limit", RELOPT_TYPE_INT, @@ -1525,6 +1545,8 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_delay)}, {"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL, offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_scale_factor)}, + {"autovacuum_vacuum_insert_scale_factor", RELOPT_TYPE_REAL, + offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_ins_scale_factor)}, {"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL, offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_scale_factor)}, {"user_catalog_table", RELOPT_TYPE_BOOL, diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index f681aafcf9..b2729f1771 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -573,6 +573,7 @@ CREATE VIEW pg_stat_all_tables AS pg_stat_get_live_tuples(C.oid) AS n_live_tup, pg_stat_get_dead_tuples(C.oid) AS n_dead_tup, pg_stat_get_mod_since_analyze(C.oid) AS n_mod_since_analyze, + pg_stat_get_ins_since_vacuum(C.oid) AS n_ins_since_vacuum, pg_stat_get_last_vacuum_time(C.oid) as last_vacuum, pg_stat_get_last_autovacuum_time(C.oid) as last_autovacuum, pg_stat_get_last_analyze_time(C.oid) as last_analyze, diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index e3a43d3296..f60a0facc4 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -117,6 +117,8 @@ int autovacuum_work_mem = -1; int autovacuum_naptime; int autovacuum_vac_thresh; double autovacuum_vac_scale; +int autovacuum_vac_ins_thresh; +double autovacuum_vac_ins_scale; int autovacuum_anl_thresh; double autovacuum_anl_scale; int autovacuum_freeze_max_age; @@ -330,7 +332,8 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts, Form_pg_class classForm, PgStat_StatTabEntry *tabentry, int effective_multixact_freeze_max_age, - bool *dovacuum, bool *doanalyze, bool *wraparound); + bool *dovacuum, bool *doanalyze, bool *wraparound, + bool *freeze_all); static void autovacuum_do_vac_analyze(autovac_table *tab, BufferAccessStrategy bstrategy); @@ -2056,6 +2059,7 @@ do_autovacuum(void) bool dovacuum; bool doanalyze; bool wraparound; + bool freeze_all; if (classForm->relkind != RELKIND_RELATION && classForm->relkind != RELKIND_MATVIEW) @@ -2096,7 +2100,8 @@ do_autovacuum(void) /* Check if it needs vacuum or analyze */ relation_needs_vacanalyze(relid, relopts, classForm, tabentry, effective_multixact_freeze_max_age, - &dovacuum, &doanalyze, &wraparound); + &dovacuum, &doanalyze, &wraparound, + &freeze_all); /* Relations that need work are added to table_oids */ if (dovacuum || doanalyze) @@ -2149,6 +2154,7 @@ do_autovacuum(void) bool dovacuum; bool doanalyze; bool wraparound; + bool freeze_all; /* * We cannot safely process other backends' temp tables, so skip 'em. @@ -2179,7 +2185,8 @@ do_autovacuum(void) relation_needs_vacanalyze(relid, relopts, classForm, tabentry, effective_multixact_freeze_max_age, - &dovacuum, &doanalyze, &wraparound); + &dovacuum, &doanalyze, &wraparound, + &freeze_all); /* ignore analyze for toast tables */ if (dovacuum) @@ -2780,6 +2787,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map, PgStat_StatDBEntry *shared; PgStat_StatDBEntry *dbentry; bool wraparound; + bool freeze_all; AutoVacOpts *avopts; /* use fresh stats */ @@ -2816,7 +2824,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map, relation_needs_vacanalyze(relid, avopts, classForm, tabentry, effective_multixact_freeze_max_age, - &dovacuum, &doanalyze, &wraparound); + &dovacuum, &doanalyze, &wraparound, + &freeze_all); /* ignore ANALYZE for toast tables */ if (classForm->relkind == RELKIND_TOASTVALUE) @@ -2889,7 +2898,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map, tab->at_params.truncate = VACOPT_TERNARY_DEFAULT; /* As of now, we don't support parallel vacuum for autovacuum */ tab->at_params.nworkers = -1; - tab->at_params.freeze_min_age = freeze_min_age; + tab->at_params.freeze_min_age = freeze_all ? 0 : freeze_min_age; tab->at_params.freeze_table_age = freeze_table_age; tab->at_params.multixact_freeze_min_age = multixact_freeze_min_age; tab->at_params.multixact_freeze_table_age = multixact_freeze_table_age; @@ -2961,7 +2970,8 @@ relation_needs_vacanalyze(Oid relid, /* output params below */ bool *dovacuum, bool *doanalyze, - bool *wraparound) + bool *wraparound, + bool *freeze_all) { bool force_vacuum; bool av_enabled; @@ -2969,12 +2979,15 @@ relation_needs_vacanalyze(Oid relid, /* constants from reloptions or GUC variables */ int vac_base_thresh, + vac_ins_base_thresh, anl_base_thresh; float4 vac_scale_factor, + vac_ins_scale_factor, anl_scale_factor; /* thresholds calculated from above constants */ float4 vacthresh, + vacinsthresh, anlthresh; /* number of vacuum (resp. analyze) tuples at this time */ @@ -3005,6 +3018,14 @@ relation_needs_vacanalyze(Oid relid, ? relopts->vacuum_threshold : autovacuum_vac_thresh; + vac_ins_scale_factor = (relopts && relopts->vacuum_ins_scale_factor >= 0) + ? relopts->vacuum_ins_scale_factor + : autovacuum_vac_ins_scale; + + vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= 0) + ? relopts->vacuum_ins_threshold + : autovacuum_vac_ins_thresh; + anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0) ? relopts->analyze_scale_factor : autovacuum_anl_scale; @@ -3023,6 +3044,9 @@ relation_needs_vacanalyze(Oid relid, av_enabled = (relopts ? relopts->enabled : true); + /* normal autovacuum shouldn't freeze aggressively */ + *freeze_all = false; + /* Force vacuum if table is at risk of wraparound */ xidForceLimit = recentXid - freeze_max_age; if (xidForceLimit < FirstNormalTransactionId) @@ -3062,6 +3086,7 @@ relation_needs_vacanalyze(Oid relid, anltuples = tabentry->changes_since_analyze; vacthresh = (float4) vac_base_thresh + vac_scale_factor * reltuples; + vacinsthresh = (float4) vac_ins_base_thresh + vac_ins_scale_factor * reltuples; anlthresh = (float4) anl_base_thresh + anl_scale_factor * reltuples; /* @@ -3076,6 +3101,17 @@ relation_needs_vacanalyze(Oid relid, /* Determine if this table needs vacuum or analyze. */ *dovacuum = force_vacuum || (vactuples > vacthresh); *doanalyze = (anltuples > anlthresh); + + /* + * If the number of inserted tuples exceeds the threshold and no + * vacuum is necessary for other reasons, run an "insert-only" vacuum + * that freezes aggressively. + */ + if (!(*dovacuum) && vacinsthresh < tabentry->inserts_since_vacuum) + { + *dovacuum = true; + *freeze_all = true; + } } else { diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index 462b4d7e06..78bd5cf90d 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -4791,6 +4791,7 @@ pgstat_get_tab_entry(PgStat_StatDBEntry *dbentry, Oid tableoid, bool create) result->n_live_tuples = 0; result->n_dead_tuples = 0; result->changes_since_analyze = 0; + result->inserts_since_vacuum = 0; result->blocks_fetched = 0; result->blocks_hit = 0; result->vacuum_timestamp = 0; @@ -5921,6 +5922,7 @@ pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len) tabentry->n_live_tuples = tabmsg->t_counts.t_delta_live_tuples; tabentry->n_dead_tuples = tabmsg->t_counts.t_delta_dead_tuples; tabentry->changes_since_analyze = tabmsg->t_counts.t_changed_tuples; + tabentry->inserts_since_vacuum = tabmsg->t_counts.t_tuples_inserted; tabentry->blocks_fetched = tabmsg->t_counts.t_blocks_fetched; tabentry->blocks_hit = tabmsg->t_counts.t_blocks_hit; @@ -5950,10 +5952,12 @@ pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len) { tabentry->n_live_tuples = 0; tabentry->n_dead_tuples = 0; + tabentry->inserts_since_vacuum = 0; } tabentry->n_live_tuples += tabmsg->t_counts.t_delta_live_tuples; tabentry->n_dead_tuples += tabmsg->t_counts.t_delta_dead_tuples; tabentry->changes_since_analyze += tabmsg->t_counts.t_changed_tuples; + tabentry->inserts_since_vacuum += tabmsg->t_counts.t_tuples_inserted; tabentry->blocks_fetched += tabmsg->t_counts.t_blocks_fetched; tabentry->blocks_hit += tabmsg->t_counts.t_blocks_hit; } @@ -6187,6 +6191,7 @@ pgstat_recv_vacuum(PgStat_MsgVacuum *msg, int len) tabentry->n_live_tuples = msg->m_live_tuples; tabentry->n_dead_tuples = msg->m_dead_tuples; + tabentry->inserts_since_vacuum = 0; if (msg->m_autovacuum) { diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index 7e6a3c1774..aac248a86e 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -196,6 +196,22 @@ pg_stat_get_mod_since_analyze(PG_FUNCTION_ARGS) } +Datum +pg_stat_get_ins_since_vacuum(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_StatTabEntry *tabentry; + + if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + result = 0; + else + result = (int64) (tabentry->inserts_since_vacuum); + + PG_RETURN_INT64(result); +} + + Datum pg_stat_get_blocks_fetched(PG_FUNCTION_ARGS) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 464f264d9a..9f4f6a4272 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -3063,6 +3063,15 @@ static struct config_int ConfigureNamesInt[] = 50, 0, INT_MAX, NULL, NULL, NULL }, + { + {"autovacuum_vacuum_insert_threshold", PGC_SIGHUP, AUTOVACUUM, + gettext_noop("Minimum number of tuple inserts prior to vacuum."), + NULL + }, + &autovacuum_vac_ins_thresh, + 10000000, 0, INT_MAX, + NULL, NULL, NULL + }, { {"autovacuum_analyze_threshold", PGC_SIGHUP, AUTOVACUUM, gettext_noop("Minimum number of tuple inserts, updates, or deletes prior to analyze."), @@ -3510,6 +3519,17 @@ static struct config_real ConfigureNamesReal[] = 0.2, 0.0, 100.0, NULL, NULL, NULL }, + + { + {"autovacuum_vacuum_insert_scale_factor", PGC_SIGHUP, AUTOVACUUM, + gettext_noop("Number of tuple inserts prior to vacuum as a fraction of reltuples."), + NULL + }, + &autovacuum_vac_ins_scale, + 0.0, 0.0, 100.0, + NULL, NULL, NULL + }, + { {"autovacuum_analyze_scale_factor", PGC_SIGHUP, AUTOVACUUM, gettext_noop("Number of tuple inserts, updates, or deletes prior to analyze as a fraction of reltuples."), diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index e58e4788a8..04ae8784f8 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -598,9 +598,13 @@ #autovacuum_naptime = 1min # time between autovacuum runs #autovacuum_vacuum_threshold = 50 # min number of row updates before # vacuum +#autovacuum_vacuum_insert_threshold = 10000000 # min number of row inserts + # before vacuum #autovacuum_analyze_threshold = 50 # min number of row updates before # analyze #autovacuum_vacuum_scale_factor = 0.2 # fraction of table size before vacuum +#autovacuum_vacuum_insert_scale_factor = 0.0 # fraction of table size before + # vacuum #autovacuum_analyze_scale_factor = 0.1 # fraction of table size before analyze #autovacuum_freeze_max_age = 200000000 # maximum XID age before forced vacuum # (change requires restart) diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index b6b08d0ccb..efc7b20659 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -1071,6 +1071,8 @@ static const char *const table_storage_parameters[] = { "autovacuum_multixact_freeze_table_age", "autovacuum_vacuum_cost_delay", "autovacuum_vacuum_cost_limit", + "autovacuum_vacuum_insert_scale_factor", + "autovacuum_vacuum_insert_threshold", "autovacuum_vacuum_scale_factor", "autovacuum_vacuum_threshold", "fillfactor", @@ -1085,6 +1087,8 @@ static const char *const table_storage_parameters[] = { "toast.autovacuum_multixact_freeze_table_age", "toast.autovacuum_vacuum_cost_delay", "toast.autovacuum_vacuum_cost_limit", + "toast.autovacuum_vacuum_insert_scale_factor", + "toast.autovacuum_vacuum_insert_threshold", "toast.autovacuum_vacuum_scale_factor", "toast.autovacuum_vacuum_threshold", "toast.log_autovacuum_min_duration", diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 07a86c7b7b..0527b785a6 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -5129,6 +5129,11 @@ proname => 'pg_stat_get_mod_since_analyze', provolatile => 's', proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', prosrc => 'pg_stat_get_mod_since_analyze' }, +{ oid => '8872', + descr => 'statistics: number of tuples inserted since last vacuum', + proname => 'pg_stat_get_ins_since_vacuum', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_ins_since_vacuum' }, { oid => '1934', descr => 'statistics: number of blocks fetched', proname => 'pg_stat_get_blocks_fetched', provolatile => 's', proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', diff --git a/src/include/pgstat.h b/src/include/pgstat.h index 3a65a51696..7ccbb3191e 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -646,6 +646,7 @@ typedef struct PgStat_StatTabEntry PgStat_Counter n_live_tuples; PgStat_Counter n_dead_tuples; PgStat_Counter changes_since_analyze; + PgStat_Counter inserts_since_vacuum; PgStat_Counter blocks_fetched; PgStat_Counter blocks_hit; diff --git a/src/include/postmaster/autovacuum.h b/src/include/postmaster/autovacuum.h index d40ed55531..7277effe03 100644 --- a/src/include/postmaster/autovacuum.h +++ b/src/include/postmaster/autovacuum.h @@ -33,6 +33,8 @@ extern int autovacuum_work_mem; extern int autovacuum_naptime; extern int autovacuum_vac_thresh; extern double autovacuum_vac_scale; +extern int autovacuum_vac_ins_thresh; +extern double autovacuum_vac_ins_scale; extern int autovacuum_anl_thresh; extern double autovacuum_anl_scale; extern int autovacuum_freeze_max_age; diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 44ed04dd3f..476d859d81 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -252,6 +252,7 @@ typedef struct AutoVacOpts { bool enabled; int vacuum_threshold; + int vacuum_ins_threshold; int analyze_threshold; int vacuum_cost_limit; int freeze_min_age; @@ -263,6 +264,7 @@ typedef struct AutoVacOpts int log_min_duration; float8 vacuum_cost_delay; float8 vacuum_scale_factor; + float8 vacuum_ins_scale_factor; float8 analyze_scale_factor; } AutoVacOpts; -- 2.21.1