From 868f4512b0f73f8bb1869e7be33ef0d6035332b3 Mon Sep 17 00:00:00 2001 From: Alena Rybakina Date: Tue, 16 Jun 2026 10:53:49 +0300 Subject: [PATCH 8/8] Extended vacuum statistics: WAL metrics for tables, indexes and database Expose the WAL generation counters in pg_stat_vacuum_tables, pg_stat_vacuum_indexes and pg_stat_vacuum_database, with documentation and regression coverage: wal_records number of WAL records generated by the vacuum wal_fpi number of WAL full page images generated by the vacuum wal_bytes total amount of WAL generated by the vacuum, in bytes A vacuum that removes tuples always emits WAL, so wal_records and wal_bytes are positive. wal_fpi depends on checkpoint timing; the regression test exercises its positive path with a dedicated vacuum run right after a CHECKPOINT. This completes the extended vacuum statistics views: every metric category is now reported for tables, indexes and the database aggregate. --- doc/src/sgml/system-views.sgml | 72 ++++++++++++++++++++++ src/backend/access/heap/vacuumlazy.c | 19 +++++- src/backend/catalog/system_views.sql | 17 ++++- src/backend/utils/activity/pgstat_vacuum.c | 4 ++ src/backend/utils/adt/pgstatfuncs.c | 32 +++++++++- src/include/catalog/pg_proc.dat | 18 +++--- src/include/pgstat.h | 5 ++ src/test/regress/expected/rules.out | 21 +++++-- src/test/regress/expected/vacuum_stats.out | 54 +++++++++++++--- src/test/regress/sql/vacuum_stats.sql | 34 +++++++++- 10 files changed, 244 insertions(+), 32 deletions(-) diff --git a/doc/src/sgml/system-views.sgml b/doc/src/sgml/system-views.sgml index 0443cbad40..50fcc3aa7d 100644 --- a/doc/src/sgml/system-views.sgml +++ b/doc/src/sgml/system-views.sgml @@ -6004,6 +6004,30 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx Number of times the failsafe mechanism was triggered to prevent transaction ID wraparound during the vacuum. + + + wal_records bigint + + + Total number of WAL records generated by the vacuum. + + + + + wal_fpi bigint + + + Total number of WAL full page images generated by the vacuum. + + + + + wal_bytes numeric + + + Total amount of WAL generated by the vacuum, in bytes. + + @@ -6175,6 +6199,30 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx Total time spent vacuuming this index, in milliseconds. + + + wal_records bigint + + + Number of WAL records generated while vacuuming this index. + + + + + wal_fpi bigint + + + Number of WAL full page images generated while vacuuming this index. + + + + + wal_bytes numeric + + + Total amount of WAL generated while vacuuming this index, in bytes. + + @@ -6305,6 +6353,30 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx Total time spent by vacuum operations in this database, in milliseconds. + + + wal_records bigint + + + Number of WAL records generated by vacuum operations in this database. + + + + + wal_fpi bigint + + + Number of WAL full page images generated by vacuum operations in this database. + + + + + wal_bytes numeric + + + Total amount of WAL generated by vacuum operations in this database, in bytes. + + diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c index 997eabf1ec..8c2e595a13 100644 --- a/src/backend/access/heap/vacuumlazy.c +++ b/src/backend/access/heap/vacuumlazy.c @@ -551,6 +551,7 @@ static void extvac_stats_end(Relation rel, LVExtStatCounters * counters, PgStat_CommonCounts * report) { + WalUsage walusage; BufferUsage bufusage; TimestampTz endtime; long secs; @@ -561,7 +562,10 @@ extvac_stats_end(Relation rel, LVExtStatCounters * counters, memset(report, 0, sizeof(PgStat_CommonCounts)); - /* Calculate diffs of global stat parameters on buffer usage. */ + /* Calculate diffs of global stat parameters on WAL and buffer usage. */ + memset(&walusage, 0, sizeof(WalUsage)); + WalUsageAccumDiff(&walusage, &pgWalUsage, &counters->walusage); + memset(&bufusage, 0, sizeof(BufferUsage)); BufferUsageAccumDiff(&bufusage, &pgBufferUsage, &counters->bufusage); @@ -576,6 +580,10 @@ extvac_stats_end(Relation rel, LVExtStatCounters * counters, report->total_blks_dirtied += bufusage.local_blks_dirtied + bufusage.shared_blks_dirtied; report->total_blks_written += bufusage.shared_blks_written; + report->wal_records += walusage.wal_records; + report->wal_fpi += walusage.wal_fpi; + report->wal_bytes += walusage.wal_bytes; + report->blk_read_time += INSTR_TIME_GET_MILLISEC(bufusage.local_blk_read_time); report->blk_read_time += INSTR_TIME_GET_MILLISEC(bufusage.shared_blk_read_time); report->blk_write_time += INSTR_TIME_GET_MILLISEC(bufusage.local_blk_write_time); @@ -689,6 +697,9 @@ accumulate_heap_vacuum_statistics(LVRelState *vacrel, PgStat_VacuumRelationCount extVacStats->common.total_blks_hit -= vacrel->extVacReportIdx.common.total_blks_hit; extVacStats->common.total_blks_read -= vacrel->extVacReportIdx.common.total_blks_read; extVacStats->common.total_blks_written -= vacrel->extVacReportIdx.common.total_blks_written; + extVacStats->common.wal_bytes -= vacrel->extVacReportIdx.common.wal_bytes; + extVacStats->common.wal_fpi -= vacrel->extVacReportIdx.common.wal_fpi; + extVacStats->common.wal_records -= vacrel->extVacReportIdx.common.wal_records; extVacStats->common.total_time -= vacrel->extVacReportIdx.common.total_time; extVacStats->common.delay_time -= vacrel->extVacReportIdx.common.delay_time; @@ -704,6 +715,9 @@ accumulate_idxs_vacuum_statistics(LVRelState *vacrel, PgStat_VacuumRelationCount vacrel->extVacReportIdx.common.total_blks_hit += extVacIdxStats->common.total_blks_hit; vacrel->extVacReportIdx.common.total_blks_read += extVacIdxStats->common.total_blks_read; vacrel->extVacReportIdx.common.total_blks_written += extVacIdxStats->common.total_blks_written; + vacrel->extVacReportIdx.common.wal_bytes += extVacIdxStats->common.wal_bytes; + vacrel->extVacReportIdx.common.wal_fpi += extVacIdxStats->common.wal_fpi; + vacrel->extVacReportIdx.common.wal_records += extVacIdxStats->common.wal_records; vacrel->extVacReportIdx.common.delay_time += extVacIdxStats->common.delay_time; vacrel->extVacReportIdx.common.total_time += extVacIdxStats->common.total_time; } @@ -730,6 +744,9 @@ extvac_accumulate_idx_report(PgStat_VacuumRelationCounts * dst, dst->common.total_blks_written += src->common.total_blks_written; dst->common.blks_fetched += src->common.blks_fetched; dst->common.blks_hit += src->common.blks_hit; + dst->common.wal_records += src->common.wal_records; + dst->common.wal_fpi += src->common.wal_fpi; + dst->common.wal_bytes += src->common.wal_bytes; dst->common.blk_read_time += src->common.blk_read_time; dst->common.blk_write_time += src->common.blk_write_time; dst->common.delay_time += src->common.delay_time; diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 11135733c2..31c97120b6 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -1586,7 +1586,10 @@ CREATE VIEW pg_stat_vacuum_tables AS S.blk_write_time AS blk_write_time, S.delay_time AS delay_time, S.total_time AS total_time, - S.wraparound_failsafe AS wraparound_failsafe + S.wraparound_failsafe AS wraparound_failsafe, + S.wal_records AS wal_records, + S.wal_fpi AS wal_fpi, + S.wal_bytes AS wal_bytes FROM pg_class C JOIN pg_namespace N ON N.oid = C.relnamespace, @@ -1615,7 +1618,11 @@ CREATE VIEW pg_stat_vacuum_indexes AS S.blk_read_time AS blk_read_time, S.blk_write_time AS blk_write_time, S.delay_time AS delay_time, - S.total_time AS total_time + S.total_time AS total_time, + + S.wal_records AS wal_records, + S.wal_fpi AS wal_fpi, + S.wal_bytes AS wal_bytes FROM pg_class C JOIN pg_index X ON C.oid = X.indrelid JOIN @@ -1641,7 +1648,11 @@ CREATE VIEW pg_stat_vacuum_database AS S.blk_read_time AS blk_read_time, S.blk_write_time AS blk_write_time, S.delay_time AS delay_time, - S.total_time AS total_time + S.total_time AS total_time, + + S.wal_records AS wal_records, + S.wal_fpi AS wal_fpi, + S.wal_bytes AS wal_bytes FROM pg_database D, LATERAL pg_stat_get_vacuum_database(D.oid) S; diff --git a/src/backend/utils/activity/pgstat_vacuum.c b/src/backend/utils/activity/pgstat_vacuum.c index d0e2eea258..c0a6bf9e97 100644 --- a/src/backend/utils/activity/pgstat_vacuum.c +++ b/src/backend/utils/activity/pgstat_vacuum.c @@ -46,6 +46,10 @@ pgstat_accumulate_common(PgStat_CommonCounts *dst, const PgStat_CommonCounts *sr ACCUMULATE_FIELD(blks_fetched); ACCUMULATE_FIELD(blks_hit); + ACCUMULATE_FIELD(wal_records); + ACCUMULATE_FIELD(wal_fpi); + ACCUMULATE_FIELD(wal_bytes); + ACCUMULATE_FIELD(blk_read_time); ACCUMULATE_FIELD(blk_write_time); ACCUMULATE_FIELD(delay_time); diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index 75ebff6d68..a03b7ef17b 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -2374,13 +2374,14 @@ pg_stat_have_stats(PG_FUNCTION_ARGS) Datum pg_stat_get_vacuum_tables(PG_FUNCTION_ARGS) { -#define PG_STAT_GET_VACUUM_TABLES_STATS_COLS 22 +#define PG_STAT_GET_VACUUM_TABLES_STATS_COLS 25 Oid relid = PG_GETARG_OID(0); PgStat_VacuumRelationCounts *extvacuum; TupleDesc tupdesc; Datum values[PG_STAT_GET_VACUUM_TABLES_STATS_COLS] = {0}; bool nulls[PG_STAT_GET_VACUUM_TABLES_STATS_COLS] = {0}; + char buf[256]; int i = 0; /* Build a tuple descriptor for our result type */ @@ -2421,6 +2422,13 @@ pg_stat_get_vacuum_tables(PG_FUNCTION_ARGS) values[i++] = Float8GetDatum(extvacuum->common.delay_time); values[i++] = Float8GetDatum(extvacuum->common.total_time); values[i++] = Int32GetDatum(extvacuum->common.wraparound_failsafe_count); + values[i++] = Int64GetDatum(extvacuum->common.wal_records); + values[i++] = Int64GetDatum(extvacuum->common.wal_fpi); + snprintf(buf, sizeof buf, UINT64_FORMAT, extvacuum->common.wal_bytes); + values[i++] = DirectFunctionCall3(numeric_in, + CStringGetDatum(buf), + ObjectIdGetDatum(0), + Int32GetDatum(-1)); Assert(i == PG_STAT_GET_VACUUM_TABLES_STATS_COLS); @@ -2434,13 +2442,14 @@ pg_stat_get_vacuum_tables(PG_FUNCTION_ARGS) Datum pg_stat_get_vacuum_indexes(PG_FUNCTION_ARGS) { -#define PG_STAT_GET_VACUUM_INDEX_STATS_COLS 13 +#define PG_STAT_GET_VACUUM_INDEX_STATS_COLS 16 Oid relid = PG_GETARG_OID(0); PgStat_VacuumRelationCounts *extvacuum; TupleDesc tupdesc; Datum values[PG_STAT_GET_VACUUM_INDEX_STATS_COLS] = {0}; bool nulls[PG_STAT_GET_VACUUM_INDEX_STATS_COLS] = {0}; + char buf[256]; int i = 0; if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) @@ -2475,6 +2484,14 @@ pg_stat_get_vacuum_indexes(PG_FUNCTION_ARGS) values[i++] = Float8GetDatum(extvacuum->common.delay_time); values[i++] = Float8GetDatum(extvacuum->common.total_time); + values[i++] = Int64GetDatum(extvacuum->common.wal_records); + values[i++] = Int64GetDatum(extvacuum->common.wal_fpi); + snprintf(buf, sizeof buf, UINT64_FORMAT, extvacuum->common.wal_bytes); + values[i++] = DirectFunctionCall3(numeric_in, + CStringGetDatum(buf), + ObjectIdGetDatum(0), + Int32GetDatum(-1)); + Assert(i == PG_STAT_GET_VACUUM_INDEX_STATS_COLS); /* Returns the record as Datum */ @@ -2487,13 +2504,14 @@ pg_stat_get_vacuum_indexes(PG_FUNCTION_ARGS) Datum pg_stat_get_vacuum_database(PG_FUNCTION_ARGS) { -#define PG_STAT_GET_VACUUM_DATABASE_STATS_COLS 11 +#define PG_STAT_GET_VACUUM_DATABASE_STATS_COLS 14 Oid dbid = PG_GETARG_OID(0); PgStat_VacuumDBCounts *extvacuum; TupleDesc tupdesc; Datum values[PG_STAT_GET_VACUUM_DATABASE_STATS_COLS] = {0}; bool nulls[PG_STAT_GET_VACUUM_DATABASE_STATS_COLS] = {0}; + char buf[256]; int i = 0; if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) @@ -2522,6 +2540,14 @@ pg_stat_get_vacuum_database(PG_FUNCTION_ARGS) values[i++] = Float8GetDatum(extvacuum->common.delay_time); values[i++] = Float8GetDatum(extvacuum->common.total_time); + values[i++] = Int64GetDatum(extvacuum->common.wal_records); + values[i++] = Int64GetDatum(extvacuum->common.wal_fpi); + snprintf(buf, sizeof buf, UINT64_FORMAT, extvacuum->common.wal_bytes); + values[i++] = DirectFunctionCall3(numeric_in, + CStringGetDatum(buf), + ObjectIdGetDatum(0), + Int32GetDatum(-1)); + Assert(i == PG_STAT_GET_VACUUM_DATABASE_STATS_COLS); /* Returns the record as Datum */ diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 75d6e2b329..4e64f42042 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -12643,9 +12643,9 @@ proname => 'pg_stat_get_vacuum_tables', prorows => 1000, provolatile => 's', prorettype => 'record', proisstrict => 'f', proretset => 't', proargtypes => 'oid', - proallargtypes => '{oid,oid,int8,int8,int8,int8,int8,int8,int8,int8,int8,int8,int8,int8,int8,int8,int8,int8,float8,float8,float8,float8,int4}', - proargmodes => '{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}', - proargnames => '{reloid,relid,pages_scanned,pages_removed,tuples_deleted,tuples_frozen,recently_dead_tuples,missed_dead_pages,missed_dead_tuples,vm_new_frozen_pages,vm_new_visible_pages,vm_new_visible_frozen_pages,total_blks_read,total_blks_hit,total_blks_dirtied,total_blks_written,rel_blks_read,rel_blks_hit,blk_read_time,blk_write_time,delay_time,total_time,wraparound_failsafe}', + proallargtypes => '{oid,oid,int8,int8,int8,int8,int8,int8,int8,int8,int8,int8,int8,int8,int8,int8,int8,int8,float8,float8,float8,float8,int4,int8,int8,numeric}', + proargmodes => '{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}', + proargnames => '{reloid,relid,pages_scanned,pages_removed,tuples_deleted,tuples_frozen,recently_dead_tuples,missed_dead_pages,missed_dead_tuples,vm_new_frozen_pages,vm_new_visible_pages,vm_new_visible_frozen_pages,total_blks_read,total_blks_hit,total_blks_dirtied,total_blks_written,rel_blks_read,rel_blks_hit,blk_read_time,blk_write_time,delay_time,total_time,wraparound_failsafe,wal_records,wal_fpi,wal_bytes}', prosrc => 'pg_stat_get_vacuum_tables' } # oid8 related functions @@ -12718,17 +12718,17 @@ proname => 'pg_stat_get_vacuum_indexes', prorows => 1000, provolatile => 's', prorettype => 'record', proisstrict => 'f', proretset => 't', proargtypes => 'oid', - proallargtypes => '{oid,oid,int8,int8,int8,int8,int8,int8,int8,int8,float8,float8,float8,float8}', - proargmodes => '{i,o,o,o,o,o,o,o,o,o,o,o,o,o}', - proargnames => '{reloid,relid,pages_deleted,tuples_deleted,total_blks_read,total_blks_hit,total_blks_dirtied,total_blks_written,rel_blks_read,rel_blks_hit,blk_read_time,blk_write_time,delay_time,total_time}', + proallargtypes => '{oid,oid,int8,int8,int8,int8,int8,int8,int8,int8,float8,float8,float8,float8,int8,int8,numeric}', + proargmodes => '{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}', + proargnames => '{reloid,relid,pages_deleted,tuples_deleted,total_blks_read,total_blks_hit,total_blks_dirtied,total_blks_written,rel_blks_read,rel_blks_hit,blk_read_time,blk_write_time,delay_time,total_time,wal_records,wal_fpi,wal_bytes}', prosrc => 'pg_stat_get_vacuum_indexes' }, { oid => '8005', descr => 'pg_stat_get_vacuum_database returns vacuum stats values for database', proname => 'pg_stat_get_vacuum_database', prorows => 1000, provolatile => 's', prorettype => 'record', proisstrict => 'f', proretset => 't', proargtypes => 'oid', - proallargtypes => '{oid,oid,int4,int8,int8,int8,int8,int4,float8,float8,float8,float8}', - proargmodes => '{i,o,o,o,o,o,o,o,o,o,o,o}', - proargnames => '{dbid,dboid,errors,db_blks_read,db_blks_hit,total_blks_dirtied,total_blks_written,wraparound_failsafe,blk_read_time,blk_write_time,delay_time,total_time}', + proallargtypes => '{oid,oid,int4,int8,int8,int8,int8,int4,float8,float8,float8,float8,int8,int8,numeric}', + proargmodes => '{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o}', + proargnames => '{dbid,dboid,errors,db_blks_read,db_blks_hit,total_blks_dirtied,total_blks_written,wraparound_failsafe,blk_read_time,blk_write_time,delay_time,total_time,wal_records,wal_fpi,wal_bytes}', prosrc => 'pg_stat_get_vacuum_database' }, ] diff --git a/src/include/pgstat.h b/src/include/pgstat.h index bfc2995389..88f2b027af 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -185,6 +185,11 @@ typedef struct PgStat_CommonCounts int64 blks_fetched; int64 blks_hit; + /* WAL */ + int64 wal_records; + int64 wal_fpi; + uint64 wal_bytes; + /* Time */ double blk_read_time; double blk_write_time; diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 952392f66d..d0d2135c06 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -2432,9 +2432,12 @@ pg_stat_vacuum_database| SELECT d.oid AS dboid, s.blk_read_time, s.blk_write_time, s.delay_time, - s.total_time + s.total_time, + s.wal_records, + s.wal_fpi, + s.wal_bytes FROM pg_database d, - LATERAL pg_stat_get_vacuum_database(d.oid) s(dboid, errors, db_blks_read, db_blks_hit, total_blks_dirtied, total_blks_written, wraparound_failsafe, blk_read_time, blk_write_time, delay_time, total_time); + LATERAL pg_stat_get_vacuum_database(d.oid) s(dboid, errors, db_blks_read, db_blks_hit, total_blks_dirtied, total_blks_written, wraparound_failsafe, blk_read_time, blk_write_time, delay_time, total_time, wal_records, wal_fpi, wal_bytes); pg_stat_vacuum_indexes| SELECT c.oid AS relid, i.oid AS indexrelid, n.nspname AS schemaname, @@ -2451,12 +2454,15 @@ pg_stat_vacuum_indexes| SELECT c.oid AS relid, s.blk_read_time, s.blk_write_time, s.delay_time, - s.total_time + s.total_time, + s.wal_records, + s.wal_fpi, + s.wal_bytes FROM (((pg_class c JOIN pg_index x ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))), - LATERAL pg_stat_get_vacuum_indexes(i.oid) s(relid, pages_deleted, tuples_deleted, total_blks_read, total_blks_hit, total_blks_dirtied, total_blks_written, rel_blks_read, rel_blks_hit, blk_read_time, blk_write_time, delay_time, total_time) + LATERAL pg_stat_get_vacuum_indexes(i.oid) s(relid, pages_deleted, tuples_deleted, total_blks_read, total_blks_hit, total_blks_dirtied, total_blks_written, rel_blks_read, rel_blks_hit, blk_read_time, blk_write_time, delay_time, total_time, wal_records, wal_fpi, wal_bytes) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char", 'm'::"char"])); pg_stat_vacuum_tables| SELECT n.nspname AS schemaname, c.relname, @@ -2481,10 +2487,13 @@ pg_stat_vacuum_tables| SELECT n.nspname AS schemaname, s.blk_write_time, s.delay_time, s.total_time, - s.wraparound_failsafe + s.wraparound_failsafe, + s.wal_records, + s.wal_fpi, + s.wal_bytes FROM (pg_class c JOIN pg_namespace n ON ((n.oid = c.relnamespace))), - LATERAL pg_stat_get_vacuum_tables(c.oid) s(relid, pages_scanned, pages_removed, tuples_deleted, tuples_frozen, recently_dead_tuples, missed_dead_pages, missed_dead_tuples, vm_new_frozen_pages, vm_new_visible_pages, vm_new_visible_frozen_pages, total_blks_read, total_blks_hit, total_blks_dirtied, total_blks_written, rel_blks_read, rel_blks_hit, blk_read_time, blk_write_time, delay_time, total_time, wraparound_failsafe) + LATERAL pg_stat_get_vacuum_tables(c.oid) s(relid, pages_scanned, pages_removed, tuples_deleted, tuples_frozen, recently_dead_tuples, missed_dead_pages, missed_dead_tuples, vm_new_frozen_pages, vm_new_visible_pages, vm_new_visible_frozen_pages, total_blks_read, total_blks_hit, total_blks_dirtied, total_blks_written, rel_blks_read, rel_blks_hit, blk_read_time, blk_write_time, delay_time, total_time, wraparound_failsafe, wal_records, wal_fpi, wal_bytes) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char", 'm'::"char"])); pg_stat_wal| SELECT wal_records, wal_fpi, diff --git a/src/test/regress/expected/vacuum_stats.out b/src/test/regress/expected/vacuum_stats.out index b5bae99946..30fadd1e6a 100644 --- a/src/test/regress/expected/vacuum_stats.out +++ b/src/test/regress/expected/vacuum_stats.out @@ -161,6 +161,38 @@ SELECT delay_time > 0 AS delay_time, (1 row) DROP TABLE vacstat_delay; +-- WAL metrics. A vacuum that removes tuples always emits WAL +-- (wal_records > 0, wal_bytes > 0). wal_fpi depends on whether a checkpoint +-- happened recently, so it is only checked for being non-negative here; the +-- positive wal_fpi path is exercised separately below. +SELECT wal_records > 0 AS wal_records, + wal_fpi >= 0 AS wal_fpi, + wal_bytes > 0 AS wal_bytes + FROM pg_stat_vacuum_tables WHERE relname = 'vacstat_t'; + wal_records | wal_fpi | wal_bytes +-------------+---------+----------- + t | t | t +(1 row) + +-- WAL full-page-image path: a CHECKPOINT immediately before the vacuum forces +-- the first modification of each page to emit a full page image, so wal_fpi +-- advances. +CREATE TABLE vacstat_fpi (id int PRIMARY KEY, v text) + WITH (autovacuum_enabled = off); +INSERT INTO vacstat_fpi SELECT g, repeat('x', 20) FROM generate_series(1, 1000) g; +DELETE FROM vacstat_fpi WHERE id % 2 = 0; +CHECKPOINT; +VACUUM vacstat_fpi; +SELECT wal_records > 0 AS wal_records, + wal_fpi > 0 AS wal_fpi, + wal_bytes > 0 AS wal_bytes + FROM pg_stat_vacuum_tables WHERE relname = 'vacstat_fpi'; + wal_records | wal_fpi | wal_bytes +-------------+---------+----------- + t | t | t +(1 row) + +DROP TABLE vacstat_fpi; -- per-index view: the primary key index is processed by the same VACUUM. -- No btree leaf empties out (interleaved deletions), so pages_deleted = 0, -- while every index entry for a removed heap tuple is deleted. The index is @@ -178,11 +210,14 @@ SELECT indexrelname, blk_read_time >= 0 AS blk_read_time, blk_write_time >= 0 AS blk_write_time, delay_time >= 0 AS delay_time, - total_time > 0 AS total_time + total_time > 0 AS total_time, + wal_records > 0 AS wal_records, + wal_fpi >= 0 AS wal_fpi, + wal_bytes > 0 AS wal_bytes FROM pg_stat_vacuum_indexes WHERE relname = 'vacstat_t' ORDER BY indexrelname; - indexrelname | pages_deleted | tuples_deleted | total_blks_read | total_blks_hit | total_blks_dirtied | total_blks_written | rel_blks_read | rel_blks_hit | blk_read_time | blk_write_time | delay_time | total_time -----------------+---------------+----------------+-----------------+----------------+--------------------+--------------------+---------------+--------------+---------------+----------------+------------+------------ - vacstat_t_pkey | t | t | t | t | t | t | t | t | t | t | t | t + indexrelname | pages_deleted | tuples_deleted | total_blks_read | total_blks_hit | total_blks_dirtied | total_blks_written | rel_blks_read | rel_blks_hit | blk_read_time | blk_write_time | delay_time | total_time | wal_records | wal_fpi | wal_bytes +----------------+---------------+----------------+-----------------+----------------+--------------------+--------------------+---------------+--------------+---------------+----------------+------------+------------+-------------+---------+----------- + vacstat_t_pkey | t | t | t | t | t | t | t | t | t | t | t | t | t | t | t (1 row) -- index page-deletion path: deleting a contiguous key range empties whole @@ -216,10 +251,13 @@ SELECT errors = 0 AS errors, blk_read_time >= 0 AS blk_read_time, blk_write_time >= 0 AS blk_write_time, delay_time >= 0 AS delay_time, - total_time > 0 AS total_time + total_time > 0 AS total_time, + wal_records > 0 AS wal_records, + wal_fpi >= 0 AS wal_fpi, + wal_bytes > 0 AS wal_bytes FROM pg_stat_vacuum_database WHERE dbname = current_database(); - errors | db_blks_read | db_blks_hit | total_blks_dirtied | total_blks_written | wraparound_failsafe | blk_read_time | blk_write_time | delay_time | total_time ---------+--------------+-------------+--------------------+--------------------+---------------------+---------------+----------------+------------+------------ - t | t | t | t | t | t | t | t | t | t + errors | db_blks_read | db_blks_hit | total_blks_dirtied | total_blks_written | wraparound_failsafe | blk_read_time | blk_write_time | delay_time | total_time | wal_records | wal_fpi | wal_bytes +--------+--------------+-------------+--------------------+--------------------+---------------------+---------------+----------------+------------+------------+-------------+---------+----------- + t | t | t | t | t | t | t | t | t | t | t | t | t (1 row) diff --git a/src/test/regress/sql/vacuum_stats.sql b/src/test/regress/sql/vacuum_stats.sql index ee517d6f44..2a366ebdf7 100644 --- a/src/test/regress/sql/vacuum_stats.sql +++ b/src/test/regress/sql/vacuum_stats.sql @@ -123,6 +123,30 @@ SELECT delay_time > 0 AS delay_time, FROM pg_stat_vacuum_tables WHERE relname = 'vacstat_delay'; DROP TABLE vacstat_delay; +-- WAL metrics. A vacuum that removes tuples always emits WAL +-- (wal_records > 0, wal_bytes > 0). wal_fpi depends on whether a checkpoint +-- happened recently, so it is only checked for being non-negative here; the +-- positive wal_fpi path is exercised separately below. +SELECT wal_records > 0 AS wal_records, + wal_fpi >= 0 AS wal_fpi, + wal_bytes > 0 AS wal_bytes + FROM pg_stat_vacuum_tables WHERE relname = 'vacstat_t'; + +-- WAL full-page-image path: a CHECKPOINT immediately before the vacuum forces +-- the first modification of each page to emit a full page image, so wal_fpi +-- advances. +CREATE TABLE vacstat_fpi (id int PRIMARY KEY, v text) + WITH (autovacuum_enabled = off); +INSERT INTO vacstat_fpi SELECT g, repeat('x', 20) FROM generate_series(1, 1000) g; +DELETE FROM vacstat_fpi WHERE id % 2 = 0; +CHECKPOINT; +VACUUM vacstat_fpi; +SELECT wal_records > 0 AS wal_records, + wal_fpi > 0 AS wal_fpi, + wal_bytes > 0 AS wal_bytes + FROM pg_stat_vacuum_tables WHERE relname = 'vacstat_fpi'; +DROP TABLE vacstat_fpi; + -- per-index view: the primary key index is processed by the same VACUUM. -- No btree leaf empties out (interleaved deletions), so pages_deleted = 0, -- while every index entry for a removed heap tuple is deleted. The index is @@ -140,7 +164,10 @@ SELECT indexrelname, blk_read_time >= 0 AS blk_read_time, blk_write_time >= 0 AS blk_write_time, delay_time >= 0 AS delay_time, - total_time > 0 AS total_time + total_time > 0 AS total_time, + wal_records > 0 AS wal_records, + wal_fpi >= 0 AS wal_fpi, + wal_bytes > 0 AS wal_bytes FROM pg_stat_vacuum_indexes WHERE relname = 'vacstat_t' ORDER BY indexrelname; -- index page-deletion path: deleting a contiguous key range empties whole @@ -170,5 +197,8 @@ SELECT errors = 0 AS errors, blk_read_time >= 0 AS blk_read_time, blk_write_time >= 0 AS blk_write_time, delay_time >= 0 AS delay_time, - total_time > 0 AS total_time + total_time > 0 AS total_time, + wal_records > 0 AS wal_records, + wal_fpi >= 0 AS wal_fpi, + wal_bytes > 0 AS wal_bytes FROM pg_stat_vacuum_database WHERE dbname = current_database(); -- 2.39.5 (Apple Git-154)