daemon
</para></entry>
</row>
+
+ <row>
+ <entry role="catalog_table_entry"><para role="column_definition">
+ <structfield>total_vacuum_time</structfield> <type>double precision</type>
+ </para>
+ <para>
+ Total time this table has been manually vacuumed, in milliseconds
+ </para></entry>
+ </row>
+
+ <row>
+ <entry role="catalog_table_entry"><para role="column_definition">
+ <structfield>total_autovacuum_time</structfield> <type>double precision</type>
+ </para>
+ <para>
+ Total time this table has been vacuumed by the autovacuum daemon,
+ in milliseconds
+ </para></entry>
+ </row>
+
+ <row>
+ <entry role="catalog_table_entry"><para role="column_definition">
+ <structfield>total_analyze_time</structfield> <type>double precision</type>
+ </para>
+ <para>
+ Total time this table has been manually analyzed, in milliseconds
+ </para></entry>
+ </row>
+
+ <row>
+ <entry role="catalog_table_entry"><para role="column_definition">
+ <structfield>total_autoanalyze_time</structfield> <type>double precision</type>
+ </para>
+ <para>
+ Total time this table has been analyzed by the autovacuum daemon,
+ in milliseconds
+ </para></entry>
+ </row>
</tbody>
</tgroup>
</table>
if (instrument)
{
pg_rusage_init(&ru0);
- starttime = GetCurrentTimestamp();
if (track_io_timing)
{
startreadtime = pgStatBlockReadTime;
}
}
+ /* Used for instrumentation and stats report */
+ starttime = GetCurrentTimestamp();
+
pgstat_progress_start_command(PROGRESS_COMMAND_VACUUM,
RelationGetRelid(rel));
rel->rd_rel->relisshared,
Max(vacrel->new_live_tuples, 0),
vacrel->recently_dead_tuples +
- vacrel->missed_dead_tuples);
+ vacrel->missed_dead_tuples,
+ starttime);
pgstat_progress_end_command();
if (instrument)
pg_stat_get_vacuum_count(C.oid) AS vacuum_count,
pg_stat_get_autovacuum_count(C.oid) AS autovacuum_count,
pg_stat_get_analyze_count(C.oid) AS analyze_count,
- pg_stat_get_autoanalyze_count(C.oid) AS autoanalyze_count
+ pg_stat_get_autoanalyze_count(C.oid) AS autoanalyze_count,
+ pg_stat_get_total_vacuum_time(C.oid) AS total_vacuum_time,
+ pg_stat_get_total_autovacuum_time(C.oid) AS total_autovacuum_time,
+ pg_stat_get_total_analyze_time(C.oid) AS total_analyze_time,
+ pg_stat_get_total_autoanalyze_time(C.oid) AS total_autoanalyze_time
FROM pg_class C LEFT JOIN
pg_index I ON C.oid = I.indrelid
LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
RestrictSearchPath();
/*
- * measure elapsed time if called with verbose or if autovacuum logging
- * requires it
+ * When verbose or autovacuum logging is used, initialize a resource usage
+ * snapshot and optionally track I/O timing.
*/
if (instrument)
{
}
pg_rusage_init(&ru0);
- starttime = GetCurrentTimestamp();
}
+ /* Used for instrumentation and stats report */
+ starttime = GetCurrentTimestamp();
+
/*
* Determine which columns to analyze
*
*/
if (!inh)
pgstat_report_analyze(onerel, totalrows, totaldeadrows,
- (va_cols == NIL));
+ (va_cols == NIL), starttime);
else if (onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
- pgstat_report_analyze(onerel, 0, 0, (va_cols == NIL));
+ pgstat_report_analyze(onerel, 0, 0, (va_cols == NIL), starttime);
/*
* If this isn't part of VACUUM ANALYZE, let index AMs do cleanup.
*/
void
pgstat_report_vacuum(Oid tableoid, bool shared,
- PgStat_Counter livetuples, PgStat_Counter deadtuples)
+ PgStat_Counter livetuples, PgStat_Counter deadtuples,
+ TimestampTz starttime)
{
PgStat_EntryRef *entry_ref;
PgStatShared_Relation *shtabentry;
PgStat_StatTabEntry *tabentry;
Oid dboid = (shared ? InvalidOid : MyDatabaseId);
TimestampTz ts;
+ PgStat_Counter elapsedtime;
if (!pgstat_track_counts)
return;
/* Store the data in the table's hash table entry. */
ts = GetCurrentTimestamp();
+ elapsedtime = TimestampDifferenceMilliseconds(starttime, ts);
/* block acquiring lock for the same reason as pgstat_report_autovac() */
entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_RELATION,
{
tabentry->last_autovacuum_time = ts;
tabentry->autovacuum_count++;
+ tabentry->total_autovacuum_time += elapsedtime;
}
else
{
tabentry->last_vacuum_time = ts;
tabentry->vacuum_count++;
+ tabentry->total_vacuum_time += elapsedtime;
}
pgstat_unlock_entry(entry_ref);
void
pgstat_report_analyze(Relation rel,
PgStat_Counter livetuples, PgStat_Counter deadtuples,
- bool resetcounter)
+ bool resetcounter, TimestampTz starttime)
{
PgStat_EntryRef *entry_ref;
PgStatShared_Relation *shtabentry;
PgStat_StatTabEntry *tabentry;
Oid dboid = (rel->rd_rel->relisshared ? InvalidOid : MyDatabaseId);
+ TimestampTz ts;
+ PgStat_Counter elapsedtime;
if (!pgstat_track_counts)
return;
deadtuples = Max(deadtuples, 0);
}
+ /* Store the data in the table's hash table entry. */
+ ts = GetCurrentTimestamp();
+ elapsedtime = TimestampDifferenceMilliseconds(starttime, ts);
+
/* block acquiring lock for the same reason as pgstat_report_autovac() */
entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_RELATION, dboid,
RelationGetRelid(rel),
if (AmAutoVacuumWorkerProcess())
{
- tabentry->last_autoanalyze_time = GetCurrentTimestamp();
+ tabentry->last_autoanalyze_time = ts;
tabentry->autoanalyze_count++;
+ tabentry->total_autoanalyze_time += elapsedtime;
}
else
{
- tabentry->last_analyze_time = GetCurrentTimestamp();
+ tabentry->last_analyze_time = ts;
tabentry->analyze_count++;
+ tabentry->total_analyze_time += elapsedtime;
}
pgstat_unlock_entry(entry_ref);
/* pg_stat_get_vacuum_count */
PG_STAT_GET_RELENTRY_INT64(vacuum_count)
+#define PG_STAT_GET_RELENTRY_FLOAT8(stat) \
+Datum \
+CppConcat(pg_stat_get_,stat)(PG_FUNCTION_ARGS) \
+{ \
+ Oid relid = PG_GETARG_OID(0); \
+ double result; \
+ PgStat_StatTabEntry *tabentry; \
+ \
+ if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) \
+ result = 0; \
+ else \
+ result = (double) (tabentry->stat); \
+ \
+ PG_RETURN_FLOAT8(result); \
+}
+
+/* pg_stat_get_total_vacuum_time */
+PG_STAT_GET_RELENTRY_FLOAT8(total_vacuum_time)
+
+/* pg_stat_get_total_autovacuum_time */
+PG_STAT_GET_RELENTRY_FLOAT8(total_autovacuum_time)
+
+/* pg_stat_get_total_analyze_time */
+PG_STAT_GET_RELENTRY_FLOAT8(total_analyze_time)
+
+/* pg_stat_get_total_autoanalyze_time */
+PG_STAT_GET_RELENTRY_FLOAT8(total_autoanalyze_time)
+
#define PG_STAT_GET_RELENTRY_TIMESTAMPTZ(stat) \
Datum \
CppConcat(pg_stat_get_,stat)(PG_FUNCTION_ARGS) \
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 202501232
+#define CATALOG_VERSION_NO 202501281
#endif
proname => 'pg_stat_get_autoanalyze_count', provolatile => 's',
proparallel => 'r', prorettype => 'int8', proargtypes => 'oid',
prosrc => 'pg_stat_get_autoanalyze_count' },
+{ oid => '8406', descr => 'total vacuum time, in milliseconds',
+ proname => 'pg_stat_get_total_vacuum_time', provolatile => 's',
+ proparallel => 'r', prorettype => 'float8', proargtypes => 'oid',
+ prosrc => 'pg_stat_get_total_vacuum_time' },
+{ oid => '8407', descr => 'total autovacuum time, in milliseconds',
+ proname => 'pg_stat_get_total_autovacuum_time', provolatile => 's',
+ proparallel => 'r', prorettype => 'float8', proargtypes => 'oid',
+ prosrc => 'pg_stat_get_total_autovacuum_time' },
+{ oid => '8408', descr => 'total analyze time, in milliseconds',
+ proname => 'pg_stat_get_total_analyze_time', provolatile => 's',
+ proparallel => 'r', prorettype => 'float8', proargtypes => 'oid',
+ prosrc => 'pg_stat_get_total_analyze_time' },
+{ oid => '8409', descr => 'total autoanalyze time, in milliseconds',
+ proname => 'pg_stat_get_total_autoanalyze_time', provolatile => 's',
+ proparallel => 'r', prorettype => 'float8', proargtypes => 'oid',
+ prosrc => 'pg_stat_get_total_autoanalyze_time' },
{ oid => '1936', descr => 'statistics: currently active backend IDs',
proname => 'pg_stat_get_backend_idset', prorows => '100', proretset => 't',
provolatile => 's', proparallel => 'r', prorettype => 'int4',
* ------------------------------------------------------------
*/
-#define PGSTAT_FILE_FORMAT_ID 0x01A5BCB1
+#define PGSTAT_FILE_FORMAT_ID 0x01A5BCB2
typedef struct PgStat_ArchiverStats
{
PgStat_Counter analyze_count;
TimestampTz last_autoanalyze_time; /* autovacuum initiated */
PgStat_Counter autoanalyze_count;
+
+ PgStat_Counter total_vacuum_time; /* times in milliseconds */
+ PgStat_Counter total_autovacuum_time;
+ PgStat_Counter total_analyze_time;
+ PgStat_Counter total_autoanalyze_time;
} PgStat_StatTabEntry;
typedef struct PgStat_WalStats
extern void pgstat_unlink_relation(Relation rel);
extern void pgstat_report_vacuum(Oid tableoid, bool shared,
- PgStat_Counter livetuples, PgStat_Counter deadtuples);
+ PgStat_Counter livetuples, PgStat_Counter deadtuples,
+ TimestampTz starttime);
extern void pgstat_report_analyze(Relation rel,
PgStat_Counter livetuples, PgStat_Counter deadtuples,
- bool resetcounter);
+ bool resetcounter, TimestampTz starttime);
/*
* If stats are enabled, but pending data hasn't been prepared yet, call
pg_stat_get_vacuum_count(c.oid) AS vacuum_count,
pg_stat_get_autovacuum_count(c.oid) AS autovacuum_count,
pg_stat_get_analyze_count(c.oid) AS analyze_count,
- pg_stat_get_autoanalyze_count(c.oid) AS autoanalyze_count
+ pg_stat_get_autoanalyze_count(c.oid) AS autoanalyze_count,
+ pg_stat_get_total_vacuum_time(c.oid) AS total_vacuum_time,
+ pg_stat_get_total_autovacuum_time(c.oid) AS total_autovacuum_time,
+ pg_stat_get_total_analyze_time(c.oid) AS total_analyze_time,
+ pg_stat_get_total_autoanalyze_time(c.oid) AS total_autoanalyze_time
FROM ((pg_class c
LEFT JOIN pg_index i ON ((c.oid = i.indrelid)))
LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace)))
vacuum_count,
autovacuum_count,
analyze_count,
- autoanalyze_count
+ autoanalyze_count,
+ total_vacuum_time,
+ total_autovacuum_time,
+ total_analyze_time,
+ total_autoanalyze_time
FROM pg_stat_all_tables
WHERE ((schemaname = ANY (ARRAY['pg_catalog'::name, 'information_schema'::name])) OR (schemaname ~ '^pg_toast'::text));
pg_stat_user_functions| SELECT p.oid AS funcid,
vacuum_count,
autovacuum_count,
analyze_count,
- autoanalyze_count
+ autoanalyze_count,
+ total_vacuum_time,
+ total_autovacuum_time,
+ total_analyze_time,
+ total_autoanalyze_time
FROM pg_stat_all_tables
WHERE ((schemaname <> ALL (ARRAY['pg_catalog'::name, 'information_schema'::name])) AND (schemaname !~ '^pg_toast'::text));
pg_stat_wal| SELECT wal_records,