]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Add pg_stat_autovacuum_scores system view.
authorNathan Bossart <nathan@postgresql.org>
Mon, 6 Apr 2026 21:56:33 +0000 (16:56 -0500)
committerNathan Bossart <nathan@postgresql.org>
Mon, 6 Apr 2026 21:56:33 +0000 (16:56 -0500)
This view contains one row for each table in the current database,
showing the current autovacuum scores for that specific table.  It
also shows whether autovacuum would vacuum or analyze the table.

Bumps catversion.

Author: Sami Imseih <samimseih@gmail.com>
Reviewed-by: Satyanarayana Narlapuram <satyanarlapuram@gmail.com>
Reviewed-by: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Reviewed-by: Robert Treat <rob@xzilla.net>
Discussion: https://postgr.es/m/CAA5RZ0s4xjMrB-VAnLccC7kY8d0-4806-Lsac-czJsdA1LXtAw%40mail.gmail.com

doc/src/sgml/maintenance.sgml
doc/src/sgml/monitoring.sgml
src/backend/catalog/system_views.sql
src/backend/postmaster/autovacuum.c
src/include/catalog/catversion.h
src/include/catalog/pg_proc.dat
src/test/regress/expected/rules.out

index 64bbc831343402e53aa55d54a2296064a841ba97..652b291de15a90ef92aa633f1ed04eb2633d6356 100644 (file)
@@ -1168,6 +1168,12 @@ analyze threshold = analyze base threshold + analyze scale factor * number of tu
      <literal>2.0</literal> effectively doubles the
      <emphasis>analyze</emphasis> component score.
     </para>
+
+    <para>
+     The <link linkend="monitoring-pg-stat-autovacuum-scores-view">
+     <structname>pg_stat_autovacuum_scores</structname></link>
+     view shows the current scores of all tables in the current database.
+    </para>
    </sect3>
   </sect2>
 
index 9678877bf3d1a062a645514f56e30f0593a53863..08d5b8245529f1f6db4d6ef566a6080f1ff4011b 100644 (file)
@@ -596,6 +596,16 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
       user tables are shown.</entry>
      </row>
 
+     <row>
+      <entry><structname>pg_stat_autovacuum_scores</structname><indexterm><primary>pg_stat_autovacuum_scores</primary></indexterm></entry>
+      <entry>
+       One row for each table in the current database, showing the current
+       autovacuum scores for that specific table.  See
+       <link linkend="monitoring-pg-stat-autovacuum-scores-view">
+       <structname>pg_stat_autovacuum_scores</structname></link> for details.
+      </entry>
+     </row>
+
      <row>
       <entry><structname>pg_stat_all_indexes</structname><indexterm><primary>pg_stat_all_indexes</primary></indexterm></entry>
       <entry>
@@ -4502,6 +4512,175 @@ description | Waiting for a newly initialized WAL file to reach durable storage
 
  </sect2>
 
+ <sect2 id="monitoring-pg-stat-autovacuum-scores-view">
+  <title><structname>pg_stat_autovacuum_scores</structname></title>
+
+  <indexterm>
+   <primary>pg_stat_autovacuum_scores</primary>
+  </indexterm>
+
+  <para>
+   The <structname>pg_stat_autovacuum_scores</structname> view will contain one
+   row for each table in the current database (including TOAST tables), showing
+   the current autovacuum scores for that specific table.  Autovacuum
+   prioritizes tables deemed eligible for processing based on their
+   <structfield>score</structfield>, with higher scores indicating higher
+   priority.  See <xref linkend="autovacuum-priority"/> for more information.
+  </para>
+
+  <para>
+   While this view generates its results the same way that autovacuum workers
+   do, it does so using the current source information, which might differ from
+   the source information that an autovacuum worker sees when it gathers its
+   list of tables to process.  Therefore, this view is not a completely
+   reliable indicator of which tables autovacuum will process and what order it
+   will process them.
+  </para>
+
+  <table id="pg-stat-autovacuum-scores-view" xreflabel="pg_stat_autovacuum_scores">
+   <title><structname>pg_stat_autovacuum_scores</structname> View</title>
+   <tgroup cols="1">
+    <thead>
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       Column Type
+      </para>
+      <para>
+       Description
+      </para></entry>
+     </row>
+    </thead>
+
+    <tbody>
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>relid</structfield> <type>oid</type>
+      </para>
+      <para>
+       Oid of the table.
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>schemaname</structfield> <type>name</type>
+      </para>
+      <para>
+       Name of the schema that the table is in.
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>relname</structfield> <type>name</type>
+      </para>
+      <para>
+       Name of the table.
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>score</structfield> <type>double precision</type>
+      </para>
+      <para>
+       Maximum value of all component scores.  This is the value that
+       autovacuum would use to sort the list of tables to process.
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>xid_score</structfield> <type>double precision</type>
+      </para>
+      <para>
+       Transaction ID age component score.  Scores greater than or equal to
+       <xref linkend="guc-autovacuum-freeze-score-weight"/> indicate that
+       autovacuum would vacuum the table for transaction ID wraparound
+       prevention.
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>mxid_score</structfield> <type>double precision</type>
+      </para>
+      <para>
+       Multixact ID age component score.  Scores greater than or equal to
+       <xref linkend="guc-autovacuum-multixact-freeze-score-weight"/> indicate
+       that autovacuum would vacuum the table for multixact ID wraparound
+       prevention.
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>vacuum_score</structfield> <type>double precision</type>
+      </para>
+      <para>
+       Vacuum component score.  Scores greater than or equal to
+       <xref linkend="guc-autovacuum-vacuum-score-weight"/> indicate that
+       autovacuum would vacuum the table (unless autovacuum is disabled).
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>vacuum_insert_score</structfield> <type>double precision</type>
+      </para>
+      <para>
+       Vacuum insert component score.  Scores greater than or equal to
+       <xref linkend="guc-autovacuum-vacuum-insert-score-weight"/> indicate
+       that autovacuum would vacuum the table (unless autovacuum is disabled).
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>analyze_score</structfield> <type>double precision</type>
+      </para>
+      <para>
+       Analyze component score.  Scores greater than or equal to
+       <xref linkend="guc-autovacuum-analyze-score-weight"/> indicate that
+       autovacuum would analyze the table (unless autovacuum is disabled).
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>do_vacuum</structfield> <type>bool</type>
+      </para>
+      <para>
+       Whether autovacuum would vacuum the table.  Note that even if the
+       component scores indicate that autovacuum would vacuum the table, this
+       may be <literal>false</literal> if autovacuum is disabled.
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>do_analyze</structfield> <type>bool</type>
+      </para>
+      <para>
+       Whether autovacuum would analyze the table.  Note that even if the
+       component scores indicate that autovacuum would analyze the table, this
+       may be <literal>false</literal> if autovacuum is disabled.
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>for_wraparound</structfield> <type>bool</type>
+      </para>
+      <para>
+       Whether autovacuum would vacuum the table for wraparound prevention.
+      </para></entry>
+     </row>
+    </tbody>
+   </tgroup>
+  </table>
+ </sect2>
+
  <sect2 id="monitoring-pg-stat-all-indexes-view">
   <title><structname>pg_stat_all_indexes</structname></title>
 
index 64ef4897571a3ced43369a60bfee8744f0771c4c..73a1c1c46703a6638d863ddfc56b40ce382b17c7 100644 (file)
@@ -795,6 +795,24 @@ CREATE VIEW pg_stat_xact_user_tables AS
     WHERE schemaname NOT IN ('pg_catalog', 'information_schema') AND
           schemaname !~ '^pg_toast';
 
+CREATE VIEW pg_stat_autovacuum_scores AS
+    SELECT
+        s.oid AS relid,
+        n.nspname AS schemaname,
+        c.relname AS relname,
+        s.score,
+        s.xid_score,
+        s.mxid_score,
+        s.vacuum_score,
+        s.vacuum_insert_score,
+        s.analyze_score,
+        s.do_vacuum,
+        s.do_analyze,
+        s.for_wraparound
+    FROM pg_stat_get_autovacuum_scores() s
+    JOIN pg_class c on c.oid = s.oid
+    LEFT JOIN pg_namespace n ON n.oid = c.relnamespace;
+
 CREATE VIEW pg_statio_all_tables AS
     SELECT
             C.oid AS relid,
index 9a38f4075d5709c35db35b5c2d80a65c81f85546..bd626a16363b12909694501ce3de0b2ca8da4058 100644 (file)
@@ -80,6 +80,7 @@
 #include "catalog/pg_namespace.h"
 #include "commands/vacuum.h"
 #include "common/int.h"
+#include "funcapi.h"
 #include "lib/ilist.h"
 #include "libpq/pqsignal.h"
 #include "miscadmin.h"
 #include "utils/syscache.h"
 #include "utils/timeout.h"
 #include "utils/timestamp.h"
+#include "utils/tuplestore.h"
 #include "utils/wait_event.h"
 
 
@@ -3627,3 +3629,74 @@ check_av_worker_gucs(void)
                                 errdetail("The server will only start up to \"autovacuum_worker_slots\" (%d) autovacuum workers at a given time.",
                                                   autovacuum_worker_slots)));
 }
+
+/*
+ * pg_stat_get_autovacuum_scores
+ *
+ * Returns current autovacuum scores for all relevant tables in the current
+ * database.
+ */
+Datum
+pg_stat_get_autovacuum_scores(PG_FUNCTION_ARGS)
+{
+       int                     effective_multixact_freeze_max_age;
+       Relation        rel;
+       TableScanDesc scan;
+       HeapTuple       tup;
+       ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+       InitMaterializedSRF(fcinfo, 0);
+
+       /* some prerequisite initialization */
+       effective_multixact_freeze_max_age = MultiXactMemberFreezeThreshold();
+       recentXid = ReadNextTransactionId();
+       recentMulti = ReadNextMultiXactId();
+
+       /* scan pg_class */
+       rel = table_open(RelationRelationId, AccessShareLock);
+       scan = table_beginscan_catalog(rel, 0, NULL);
+       while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
+       {
+               Form_pg_class form = (Form_pg_class) GETSTRUCT(tup);
+               AutoVacOpts *avopts;
+               bool            dovacuum;
+               bool            doanalyze;
+               bool            wraparound;
+               AutoVacuumScores scores;
+               Datum           vals[10];
+               bool            nulls[10] = {false};
+
+               /* skip ineligible entries */
+               if (form->relkind != RELKIND_RELATION &&
+                       form->relkind != RELKIND_MATVIEW &&
+                       form->relkind != RELKIND_TOASTVALUE)
+                       continue;
+               if (form->relpersistence == RELPERSISTENCE_TEMP)
+                       continue;
+
+               avopts = extract_autovac_opts(tup, RelationGetDescr(rel));
+               relation_needs_vacanalyze(form->oid, avopts, form,
+                                                                 effective_multixact_freeze_max_age, 0,
+                                                                 &dovacuum, &doanalyze, &wraparound,
+                                                                 &scores);
+               if (avopts)
+                       pfree(avopts);
+
+               vals[0] = ObjectIdGetDatum(form->oid);
+               vals[1] = Float8GetDatum(scores.max);
+               vals[2] = Float8GetDatum(scores.xid);
+               vals[3] = Float8GetDatum(scores.mxid);
+               vals[4] = Float8GetDatum(scores.vac);
+               vals[5] = Float8GetDatum(scores.vac_ins);
+               vals[6] = Float8GetDatum(scores.anl);
+               vals[7] = BoolGetDatum(dovacuum);
+               vals[8] = BoolGetDatum(doanalyze);
+               vals[9] = BoolGetDatum(wraparound);
+
+               tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, vals, nulls);
+       }
+       table_endscan(scan);
+       table_close(rel, AccessShareLock);
+
+       return (Datum) 0;
+}
index 0cee5315b59155c3b97c8841eec173ad60389007..1602962dbe135828c25344a3123951ae3562307c 100644 (file)
@@ -57,6 +57,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     202604051
+#define CATALOG_VERSION_NO     202604061
 
 #endif
index 3ea17fc562956cb93e664ff838eb5776be8744dd..99fa9a6ede29e103b4625a48e6c60a1017945b62 100644 (file)
   proname => 'pg_stat_get_total_autoanalyze_time', provolatile => 's',
   proparallel => 'r', prorettype => 'float8', proargtypes => 'oid',
   prosrc => 'pg_stat_get_total_autoanalyze_time' },
+{ oid => '8409', descr => 'autovacuum scores',
+  proname => 'pg_stat_get_autovacuum_scores', prorows => '100', proretset => 't',
+  provolatile => 's', proparallel => 'r', prorettype => 'record', proargtypes => '',
+  proallargtypes => '{oid,float8,float8,float8,float8,float8,float8,bool,bool,bool}',
+  proargmodes => '{o,o,o,o,o,o,o,o,o,o}',
+  proargnames => '{oid,score,xid_score,mxid_score,vacuum_score,vacuum_insert_score,analyze_score,do_vacuum,do_analyze,for_wraparound}',
+  prosrc => 'pg_stat_get_autovacuum_scores' },
 { oid => '1936', descr => 'statistics: currently active backend IDs',
   proname => 'pg_stat_get_backend_idset', prorows => '100', proretset => 't',
   provolatile => 's', proparallel => 'r', prorettype => 'int4',
index 45994ff0222c26096cbe9802e7c93f1a93498d12..a65a5bf0c4fbc4970fb741e0239ab1a0e40012c6 100644 (file)
@@ -1860,6 +1860,21 @@ pg_stat_archiver| SELECT archived_count,
     last_failed_time,
     stats_reset
    FROM pg_stat_get_archiver() s(archived_count, last_archived_wal, last_archived_time, failed_count, last_failed_wal, last_failed_time, stats_reset);
+pg_stat_autovacuum_scores| SELECT s.oid AS relid,
+    n.nspname AS schemaname,
+    c.relname,
+    s.score,
+    s.xid_score,
+    s.mxid_score,
+    s.vacuum_score,
+    s.vacuum_insert_score,
+    s.analyze_score,
+    s.do_vacuum,
+    s.do_analyze,
+    s.for_wraparound
+   FROM ((pg_stat_get_autovacuum_scores() s(oid, score, xid_score, mxid_score, vacuum_score, vacuum_insert_score, analyze_score, do_vacuum, do_analyze, for_wraparound)
+     JOIN pg_class c ON ((c.oid = s.oid)))
+     LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace)));
 pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
     pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
     pg_stat_get_buf_alloc() AS buffers_alloc,