Add pg_stat_autovacuum_scores system view.

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
This commit is contained in:
Nathan Bossart 2026-04-06 16:56:33 -05:00
parent b3a37ffbc5
commit 87f61f0c82
7 changed files with 299 additions and 1 deletions

View 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>

View 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>

View 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,

View 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"
@ -112,6 +113,7 @@
#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;
}

View file

@ -57,6 +57,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 202604051
#define CATALOG_VERSION_NO 202604061
#endif

View file

@ -5673,6 +5673,13 @@
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',

View 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,