Trigger autovacuum based on number of INSERTs
authorDavid Rowley <drowley@postgresql.org>
Sat, 28 Mar 2020 06:20:12 +0000 (19:20 +1300)
committerDavid Rowley <drowley@postgresql.org>
Sat, 28 Mar 2020 06:20:12 +0000 (19:20 +1300)
Traditionally autovacuum has only ever invoked a worker based on the
estimated number of dead tuples in a table and for anti-wraparound
purposes. For the latter, with certain classes of tables such as
insert-only tables, anti-wraparound vacuums could be the first vacuum that
the table ever receives. This could often lead to autovacuum workers being
busy for extended periods of time due to having to potentially freeze
every page in the table. This could be particularly bad for very large
tables. New clusters, or recently pg_restored clusters could suffer even
more as many large tables may have the same relfrozenxid, which could
result in large numbers of tables requiring an anti-wraparound vacuum all
at once.

Here we aim to reduce the work required by anti-wraparound and aggressive
vacuums in general, by triggering autovacuum when the table has received
enough INSERTs. This is controlled by adding two new GUCs and reloptions;
autovacuum_vacuum_insert_threshold and
autovacuum_vacuum_insert_scale_factor. These work exactly the same as the
existing scale factor and threshold controls, only base themselves off the
number of inserts since the last vacuum, rather than the number of dead
tuples. New controls were added rather than reusing the existing
controls, to allow these new vacuums to be tuned independently and perhaps
even completely disabled altogether, which can be done by setting
autovacuum_vacuum_insert_threshold to -1.

We make no attempt to skip index cleanup operations on these vacuums as
they may trigger for an insert-mostly table which continually doesn't have
enough dead tuples to trigger an autovacuum for the purpose of removing
those dead tuples. If we were to skip cleaning the indexes in this case,
then it is possible for the index(es) to become bloated over time.

There are additional benefits to triggering autovacuums based on inserts,
as tables which never contain enough dead tuples to trigger an autovacuum
are now more likely to receive a vacuum, which can mark more of the table
as "allvisible" and encourage the query planner to make use of Index Only
Scans.

Currently, we still obey vacuum_freeze_min_age when triggering these new
autovacuums based on INSERTs. For large insert-only tables, it may be
beneficial to lower the table's autovacuum_freeze_min_age so that tuples
are eligible to be frozen sooner. Here we've opted not to zero that for
these types of vacuums, since the table may just be insert-mostly and we
may otherwise freeze tuples that are still destined to be updated or
removed in the near future.

There was some debate to what exactly the new scale factor and threshold
should default to. For now, these are set to 0.2 and 1000, respectively.
There may be some motivation to adjust these before the release.

Author: Laurenz Albe, Darafei Praliaskouski
Reviewed-by: Alvaro Herrera, Masahiko Sawada, Chris Travers, Andres Freund, Justin Pryzby
Discussion: https://postgr.es/m/CAC8Q8t%2Bj36G_bLF%3D%2B0iMo6jGNWnLnWb1tujXuJr-%2Bx8ZCCTqoQ%40mail.gmail.com

18 files changed:
doc/src/sgml/config.sgml
doc/src/sgml/maintenance.sgml
doc/src/sgml/monitoring.sgml
doc/src/sgml/ref/create_table.sgml
src/backend/access/common/reloptions.c
src/backend/catalog/system_views.sql
src/backend/postmaster/autovacuum.c
src/backend/postmaster/pgstat.c
src/backend/utils/adt/pgstatfuncs.c
src/backend/utils/misc/guc.c
src/backend/utils/misc/postgresql.conf.sample
src/bin/psql/tab-complete.c
src/include/catalog/catversion.h
src/include/catalog/pg_proc.dat
src/include/pgstat.h
src/include/postmaster/autovacuum.h
src/include/utils/rel.h
src/test/regress/expected/rules.out

index 557af3cf6ee70bf431f803d7d5103c748def0ac2..2de21903a1516759c034775fe929459721a5d4d1 100644 (file)
@@ -7313,6 +7313,28 @@ 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 1000 tuples.  If -1 is specified, autovacuum will not
+        trigger a <command>VACUUM</command> operation on any tables based on
+        the number of inserts.
+        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>
@@ -7354,6 +7376,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.2 (20% of table size).
+        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>
index ec8bdcd7a4982dc31c5aca6e20fdd65f3ebe7357..a0e0f34c25f9026d9c07b67976671baaba152b69 100644 (file)
@@ -777,13 +777,33 @@ vacuum threshold = vacuum base threshold + vacuum scale factor * number of tuple
     <xref linkend="guc-autovacuum-vacuum-scale-factor"/>,
     and the number of tuples is
     <structname>pg_class</structname>.<structfield>reltuples</structfield>.
-    The number of obsolete tuples is obtained from the statistics
-    collector; it is a semi-accurate count updated by each
-    <command>UPDATE</command> and <command>DELETE</command> operation.  (It
-    is only semi-accurate because some information might be lost under heavy
-    load.)  If the <structfield>relfrozenxid</structfield> value of the table is more
-    than <varname>vacuum_freeze_table_age</varname> transactions old, an aggressive
-    vacuum is performed to freeze old tuples and advance
+   </para>
+
+   <para>
+    The table is also vacuumed if the number of tuples inserted since the last
+    vacuum has exceeded the defined insert threshold, which is defined as:
+<programlisting>
+vacuum insert threshold = vacuum base insert threshold + vacuum insert scale factor * number of tuples
+</programlisting>
+    where the vacuum insert base threshold is
+    <xref linkend="guc-autovacuum-vacuum-insert-threshold"/>,
+    and vacuum insert scale factor is
+    <xref linkend="guc-autovacuum-vacuum-insert-scale-factor"/>.
+    Such vacuums may allow portions of the table to be marked as
+    <firstterm>all visible</firstterm> and also allow tuples to be frozen, which
+    can reduce the work required in subsequent vacuums.
+    For tables which receive <command>INSERT</command> operations but no or
+    almost no <command>UPDATE</command>/<command>DELETE</command> operations,
+    it may be beneficial to lower the table's
+    <xref linkend="reloption-autovacuum-freeze-min-age"/> as this may allow
+    tuples to be frozen by earlier vacuums.  The number of obsolete tuples and
+    the number of inserted tuples are obtained from the statistics collector;
+    it is a semi-accurate count updated by each <command>UPDATE</command>,
+    <command>DELETE</command> and <command>INSERT</command> operation.  (It is
+    only semi-accurate because some information might be lost under heavy
+    load.)  If the <structfield>relfrozenxid</structfield> value of the table
+    is more than <varname>vacuum_freeze_table_age</varname> transactions old,
+    an aggressive vacuum is performed to freeze old tuples and advance
     <structfield>relfrozenxid</structfield>; otherwise, only pages that have been modified
     since the last vacuum are scanned.
    </para>
index 270178d57e95833731a33cbe6dcc498c37d0a74f..220b8164c3513912f56e909ca8a1136dae3f94c5 100644 (file)
@@ -2861,6 +2861,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>
index 15b50c56f05a457546fec3c58523e85e2733be49..9f8b59de50a829600e67d4bf48a6898dc6e4511b 100644 (file)
@@ -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.  The special value of -1 may be used to disable insert vacuums on the table.
+     </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>
index ec207d3b26c0e48a8b581f792bc022ed7249efb6..e136116d7bac919fc69b6cbfc6695026e88a9763 100644 (file)
@@ -233,6 +233,15 @@ static relopt_int intRelOpts[] =
        },
        -1, 0, INT_MAX
    },
+   {
+       {
+           "autovacuum_vacuum_insert_threshold",
+           "Minimum number of tuple inserts prior to vacuum, or -1 to disable insert vacuums",
+           RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
+           ShareUpdateExclusiveLock
+       },
+       -2, -1, INT_MAX
+   },
    {
        {
            "autovacuum_analyze_threshold",
@@ -398,6 +407,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",
@@ -1514,6 +1532,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,
@@ -1538,6 +1558,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,
index 5a6dc616301656c935486667897e6c3e475b310d..83d00c6cdef9ab4318858af3ae825c4ab7007734 100644 (file)
@@ -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,
index da75e755f0ff769a47796757fe84bfd430c09bba..7e97ffab27d4e9e135af4fe782d21c01723aa362 100644 (file)
@@ -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;
@@ -2969,16 +2971,20 @@ 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 */
    float4      vactuples,
+               instuples,
                anltuples;
 
    /* freeze parameters */
@@ -3005,6 +3011,15 @@ 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;
+
+   /* -1 is used to disable insert vacuums */
+   vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1)
+       ? relopts->vacuum_ins_threshold
+       : autovacuum_vac_ins_thresh;
+
    anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0)
        ? relopts->analyze_scale_factor
        : autovacuum_anl_scale;
@@ -3059,9 +3074,11 @@ relation_needs_vacanalyze(Oid relid,
    {
        reltuples = classForm->reltuples;
        vactuples = tabentry->n_dead_tuples;
+       instuples = tabentry->inserts_since_vacuum;
        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;
 
        /*
@@ -3069,12 +3086,18 @@ relation_needs_vacanalyze(Oid relid,
         * reset, because if that happens, the last vacuum and analyze counts
         * will be reset too.
         */
-       elog(DEBUG3, "%s: vac: %.0f (threshold %.0f), anl: %.0f (threshold %.0f)",
-            NameStr(classForm->relname),
-            vactuples, vacthresh, anltuples, anlthresh);
+       if (vac_ins_base_thresh >= 0)
+           elog(DEBUG3, "%s: vac: %.0f (threshold %.0f), ins: %.0f (threshold %.0f), anl: %.0f (threshold %.0f)",
+                NameStr(classForm->relname),
+                vactuples, vacthresh, instuples, vacinsthresh, anltuples, anlthresh);
+       else
+           elog(DEBUG3, "%s: vac: %.0f (threshold %.0f), ins: (disabled), anl: %.0f (threshold %.0f)",
+                NameStr(classForm->relname),
+                vactuples, vacthresh, anltuples, anlthresh);
 
        /* Determine if this table needs vacuum or analyze. */
-       *dovacuum = force_vacuum || (vactuples > vacthresh);
+       *dovacuum = force_vacuum || (vactuples > vacthresh) ||
+                   (vac_ins_base_thresh >= 0 && instuples > vacinsthresh);
        *doanalyze = (anltuples > anlthresh);
    }
    else
index 4763c24be944753ded9e2d656a06221b663456da..ab42df7e1b47933b3fb4c471e19d3d1a1ede4c36 100644 (file)
@@ -4701,6 +4701,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;
@@ -5831,6 +5832,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;
 
@@ -5860,10 +5862,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;
        }
@@ -6098,6 +6102,18 @@ pgstat_recv_vacuum(PgStat_MsgVacuum *msg, int len)
    tabentry->n_live_tuples = msg->m_live_tuples;
    tabentry->n_dead_tuples = msg->m_dead_tuples;
 
+   /*
+    * It is quite possible that a non-aggressive VACUUM ended up skipping
+    * various pages, however, we'll zero the insert counter here regardless.
+    * It's currently used only to track when we need to perform an
+    * "insert" autovacuum, which are mainly intended to freeze newly inserted
+    * tuples.  Zeroing this may just mean we'll not try to vacuum the table
+    * again until enough tuples have been inserted to trigger another insert
+    * autovacuum.  An anti-wraparound autovacuum will catch any persistent
+    * stragglers.
+    */
+   tabentry->inserts_since_vacuum = 0;
+
    if (msg->m_autovacuum)
    {
        tabentry->autovac_vacuum_timestamp = msg->m_vacuumtime;
index cea01534a5ef3875c9fb4877963877ea90118b97..6d66ff8b4484fcfdf7d6e6f6017da5f21e1b873e 100644 (file)
@@ -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)
 {
index 53665971f5355b5c9f94a927ed1928db8f4c9ad5..79bc7ac8cac4a7a8c80da6aad8a987f91798c853 100644 (file)
@@ -3102,6 +3102,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, or -1 to disable insert vacuums"),
+           NULL
+       },
+       &autovacuum_vac_ins_thresh,
+       1000, -1, INT_MAX,
+       NULL, NULL, NULL
+   },
    {
        {"autovacuum_analyze_threshold", PGC_SIGHUP, AUTOVACUUM,
            gettext_noop("Minimum number of tuple inserts, updates, or deletes prior to analyze."),
@@ -3549,6 +3558,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.2, 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."),
index f01e43b8189d23480bad94d388b8466295476ca7..e9f8ca775da956822d1558ed082a571dd9f570b7 100644 (file)
 #autovacuum_naptime = 1min     # time between autovacuum runs
 #autovacuum_vacuum_threshold = 50  # min number of row updates before
                    # vacuum
+#autovacuum_vacuum_insert_threshold = 1000 # min number of row inserts
+                   # before vacuum. -1 disables insert
+                   # vacuums
 #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.2   # fraction of inserts over table
+                   # size before insert 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)
index ae35fa4aa98d9c54d06cdcf83d642b695131fcdb..ca8f0d75a62738bb397486b007f5e2f9548dfe63 100644 (file)
@@ -1078,6 +1078,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",
@@ -1092,6 +1094,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",
index 8aa18483e4e9527887ac1038aa49c2d1a960d085..58ff619e8a58560d89d0299cacf74cba5d28a053 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 202003241
+#define CATALOG_VERSION_NO 202003281
 
 #endif
index 87d25d4a4bdecb77d0969f2df8e6da363cc0ef49..ac8ad8dbf08e92a444602cba04b040307ceb9b9b 100644 (file)
   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',
index a07012bf4bac39dd5b0d09608bb3fcaf2da2e7b5..763c1ee2bdd4ebff630e0dcc39ec27d910f65c72 100644 (file)
@@ -647,6 +647,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;
index d40ed55531d2f807b6ca2d2b552bd2a56ace2308..7277effe03485468b713e1ba98acec86b457bbf9 100644 (file)
@@ -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;
index 39cdcddc2b195bfa6845c9de0ecb53e5a57407ed..2a13d8aad0cfa307908c6be354a773d4aa6e0d00 100644 (file)
@@ -257,6 +257,7 @@ typedef struct AutoVacOpts
 {
    bool        enabled;
    int         vacuum_threshold;
+   int         vacuum_ins_threshold;
    int         analyze_threshold;
    int         vacuum_cost_limit;
    int         freeze_min_age;
@@ -268,6 +269,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;
 
index a2077bbad4d8e7b49efb98f0a479f54bacb88569..7245b0e13b89126920da2ec152a76a456a9f41fb 100644 (file)
@@ -1778,6 +1778,7 @@ pg_stat_all_tables| SELECT c.oid AS relid,
     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,
@@ -2052,6 +2053,7 @@ pg_stat_sys_tables| SELECT pg_stat_all_tables.relid,
     pg_stat_all_tables.n_live_tup,
     pg_stat_all_tables.n_dead_tup,
     pg_stat_all_tables.n_mod_since_analyze,
+    pg_stat_all_tables.n_ins_since_vacuum,
     pg_stat_all_tables.last_vacuum,
     pg_stat_all_tables.last_autovacuum,
     pg_stat_all_tables.last_analyze,
@@ -2095,6 +2097,7 @@ pg_stat_user_tables| SELECT pg_stat_all_tables.relid,
     pg_stat_all_tables.n_live_tup,
     pg_stat_all_tables.n_dead_tup,
     pg_stat_all_tables.n_mod_since_analyze,
+    pg_stat_all_tables.n_ins_since_vacuum,
     pg_stat_all_tables.last_vacuum,
     pg_stat_all_tables.last_autovacuum,
     pg_stat_all_tables.last_analyze,