Skip to content

Commit 4c468b3

Browse files
committed
Track last time for statistics reset on databases and bgwriter
Tracks one counter for each database, which is reset whenever the statistics for any individual object inside the database is reset, and one counter for the background writer. Tomas Vondra, reviewed by Greg Smith
1 parent a2e61ec commit 4c468b3

File tree

8 files changed

+79
-9
lines changed

8 files changed

+79
-9
lines changed

doc/src/sgml/monitoring.sgml

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re
267267
by backends (that is, not by the background writer), how many times
268268
those backends had to execute their own fsync calls (normally the
269269
background writer handles those even when the backend does its own
270-
write), and total buffers allocated.
270+
write), total buffers allocated, and time of last statistics reset.
271271
</entry>
272272
</row>
273273

@@ -278,9 +278,9 @@ postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re
278278
number of transactions committed and rolled back in that database,
279279
total disk blocks read, total buffer hits (i.e., block
280280
read requests avoided by finding the block already in buffer cache),
281-
number of rows returned, fetched, inserted, updated and deleted, and
281+
number of rows returned, fetched, inserted, updated and deleted, the
282282
total number of queries cancelled due to conflict with recovery (on
283-
standby servers).
283+
standby servers), and time of last statistics reset.
284284
</entry>
285285
</row>
286286

@@ -662,6 +662,19 @@ postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re
662662
</entry>
663663
</row>
664664

665+
<row>
666+
<entry><literal><function>pg_stat_get_db_stat_reset_time</function>(<type>oid</type>)</literal></entry>
667+
<entry><type>timestamptz</type></entry>
668+
<entry>
669+
Time of the last statistics reset for the database. Initialized to the
670+
system time during the first connection to each database. The reset time
671+
is updated when you call <function>pg_stat_reset</function> on the
672+
database, as well as upon execution of
673+
<function>pg_stat_reset_single_table_counters</function> against any
674+
table or index in it.
675+
</entry>
676+
</row>
677+
665678
<row>
666679
<entry><literal><function>pg_stat_get_numscans</function>(<type>oid</type>)</literal></entry>
667680
<entry><type>bigint</type></entry>
@@ -1126,6 +1139,16 @@ postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re
11261139
</entry>
11271140
</row>
11281141

1142+
<row>
1143+
<entry><literal><function>pg_stat_get_bgwriter_stat_reset_time()</function></literal></entry>
1144+
<entry><type>timestamptz</type></entry>
1145+
<entry>
1146+
Time of the last statistics reset for the background writer, updated
1147+
when executing <function>pg_stat_reset_shared('bgwriter')</function>
1148+
on the database cluster.
1149+
</entry>
1150+
</row>
1151+
11291152
<row>
11301153
<entry><literal><function>pg_stat_get_buf_written_backend()</function></literal></entry>
11311154
<entry><type>bigint</type></entry>

src/backend/catalog/system_views.sql

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,8 @@ CREATE VIEW pg_stat_database AS
530530
pg_stat_get_db_tuples_inserted(D.oid) AS tup_inserted,
531531
pg_stat_get_db_tuples_updated(D.oid) AS tup_updated,
532532
pg_stat_get_db_tuples_deleted(D.oid) AS tup_deleted,
533-
pg_stat_get_db_conflict_all(D.oid) AS conflicts
533+
pg_stat_get_db_conflict_all(D.oid) AS conflicts,
534+
pg_stat_get_db_stat_reset_time(D.oid) AS stats_reset
534535
FROM pg_database D;
535536

536537
CREATE VIEW pg_stat_database_conflicts AS
@@ -577,7 +578,8 @@ CREATE VIEW pg_stat_bgwriter AS
577578
pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
578579
pg_stat_get_buf_written_backend() AS buffers_backend,
579580
pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
580-
pg_stat_get_buf_alloc() AS buffers_alloc;
581+
pg_stat_get_buf_alloc() AS buffers_alloc,
582+
pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
581583

582584
CREATE VIEW pg_user_mappings AS
583585
SELECT

src/backend/postmaster/pgstat.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3160,6 +3160,8 @@ pgstat_get_db_entry(Oid databaseid, bool create)
31603160
result->n_conflict_bufferpin = 0;
31613161
result->n_conflict_startup_deadlock = 0;
31623162

3163+
result->stat_reset_timestamp = GetCurrentTimestamp();
3164+
31633165
memset(&hash_ctl, 0, sizeof(hash_ctl));
31643166
hash_ctl.keysize = sizeof(Oid);
31653167
hash_ctl.entrysize = sizeof(PgStat_StatTabEntry);
@@ -3439,6 +3441,12 @@ pgstat_read_statsfile(Oid onlydb, bool permanent)
34393441
*/
34403442
memset(&globalStats, 0, sizeof(globalStats));
34413443

3444+
/*
3445+
* Set the current timestamp (will be kept only in case we can't load an
3446+
* existing statsfile.
3447+
*/
3448+
globalStats.stat_reset_timestamp = GetCurrentTimestamp();
3449+
34423450
/*
34433451
* Try to open the status file. If it doesn't exist, the backends simply
34443452
* return zero for anything and the collector simply starts from scratch
@@ -4052,6 +4060,8 @@ pgstat_recv_resetcounter(PgStat_MsgResetcounter *msg, int len)
40524060
dbentry->n_tuples_deleted = 0;
40534061
dbentry->last_autovac_time = 0;
40544062

4063+
dbentry->stat_reset_timestamp = GetCurrentTimestamp();
4064+
40554065
memset(&hash_ctl, 0, sizeof(hash_ctl));
40564066
hash_ctl.keysize = sizeof(Oid);
40574067
hash_ctl.entrysize = sizeof(PgStat_StatTabEntry);
@@ -4083,6 +4093,7 @@ pgstat_recv_resetsharedcounter(PgStat_MsgResetsharedcounter *msg, int len)
40834093
{
40844094
/* Reset the global background writer statistics for the cluster. */
40854095
memset(&globalStats, 0, sizeof(globalStats));
4096+
globalStats.stat_reset_timestamp = GetCurrentTimestamp();
40864097
}
40874098

40884099
/*
@@ -4107,6 +4118,8 @@ pgstat_recv_resetsinglecounter(PgStat_MsgResetsinglecounter *msg, int len)
41074118
if (!dbentry)
41084119
return;
41094120

4121+
/* Set the reset timestamp for the whole database */
4122+
dbentry->stat_reset_timestamp = GetCurrentTimestamp();
41104123

41114124
/* Remove object if it exists, ignore it if not */
41124125
if (msg->m_resettype == RESET_TABLE)

src/backend/utils/adt/pgstatfuncs.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,14 @@ extern Datum pg_stat_get_db_conflict_snapshot(PG_FUNCTION_ARGS);
7777
extern Datum pg_stat_get_db_conflict_bufferpin(PG_FUNCTION_ARGS);
7878
extern Datum pg_stat_get_db_conflict_startup_deadlock(PG_FUNCTION_ARGS);
7979
extern Datum pg_stat_get_db_conflict_all(PG_FUNCTION_ARGS);
80+
extern Datum pg_stat_get_db_stat_reset_time(PG_FUNCTION_ARGS);
8081

8182
extern Datum pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS);
8283
extern Datum pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS);
8384
extern Datum pg_stat_get_bgwriter_buf_written_checkpoints(PG_FUNCTION_ARGS);
8485
extern Datum pg_stat_get_bgwriter_buf_written_clean(PG_FUNCTION_ARGS);
8586
extern Datum pg_stat_get_bgwriter_maxwritten_clean(PG_FUNCTION_ARGS);
87+
extern Datum pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS);
8688
extern Datum pg_stat_get_buf_written_backend(PG_FUNCTION_ARGS);
8789
extern Datum pg_stat_get_buf_fsync_backend(PG_FUNCTION_ARGS);
8890
extern Datum pg_stat_get_buf_alloc(PG_FUNCTION_ARGS);
@@ -1135,6 +1137,24 @@ pg_stat_get_db_tuples_deleted(PG_FUNCTION_ARGS)
11351137
PG_RETURN_INT64(result);
11361138
}
11371139

1140+
Datum
1141+
pg_stat_get_db_stat_reset_time(PG_FUNCTION_ARGS)
1142+
{
1143+
Oid dbid = PG_GETARG_OID(0);
1144+
TimestampTz result;
1145+
PgStat_StatDBEntry *dbentry;
1146+
1147+
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1148+
result = 0;
1149+
else
1150+
result = dbentry->stat_reset_timestamp;
1151+
1152+
if (result == 0)
1153+
PG_RETURN_NULL();
1154+
else
1155+
PG_RETURN_TIMESTAMPTZ(result);
1156+
}
1157+
11381158
Datum
11391159
pg_stat_get_db_conflict_tablespace(PG_FUNCTION_ARGS)
11401160
{
@@ -1260,6 +1280,12 @@ pg_stat_get_bgwriter_maxwritten_clean(PG_FUNCTION_ARGS)
12601280
PG_RETURN_INT64(pgstat_fetch_global()->maxwritten_clean);
12611281
}
12621282

1283+
Datum
1284+
pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS)
1285+
{
1286+
PG_RETURN_TIMESTAMPTZ(pgstat_fetch_global()->stat_reset_timestamp);
1287+
}
1288+
12631289
Datum
12641290
pg_stat_get_buf_written_backend(PG_FUNCTION_ARGS)
12651291
{

src/include/catalog/catversion.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/* yyyymmddN */
56-
#define CATALOG_VERSION_NO 201102091
56+
#define CATALOG_VERSION_NO 201102101
5757

5858
#endif

src/include/catalog/pg_proc.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3131,6 +3131,8 @@ DATA(insert OID = 3069 ( pg_stat_get_db_conflict_startup_deadlock PGNSP PGUID 1
31313131
DESCR("statistics: recovery conflicts in database caused by buffer deadlock");
31323132
DATA(insert OID = 3070 ( pg_stat_get_db_conflict_all PGNSP PGUID 12 1 0 0 f f f t f s 1 0 20 "26" _null_ _null_ _null_ _null_ pg_stat_get_db_conflict_all _null_ _null_ _null_ ));
31333133
DESCR("statistics: recovery conflicts in database");
3134+
DATA(insert OID = 3074 ( pg_stat_get_db_stat_reset_time PGNSP PGUID 12 1 0 0 f f f t f s 1 0 1184 "26" _null_ _null_ _null_ _null_ pg_stat_get_db_stat_reset_time _null_ _null_ _null_ ));
3135+
DESCR("statistics: last reset for a database");
31343136
DATA(insert OID = 2769 ( pg_stat_get_bgwriter_timed_checkpoints PGNSP PGUID 12 1 0 0 f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_bgwriter_timed_checkpoints _null_ _null_ _null_ ));
31353137
DESCR("statistics: number of timed checkpoints started by the bgwriter");
31363138
DATA(insert OID = 2770 ( pg_stat_get_bgwriter_requested_checkpoints PGNSP PGUID 12 1 0 0 f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_bgwriter_requested_checkpoints _null_ _null_ _null_ ));
@@ -3141,6 +3143,8 @@ DATA(insert OID = 2772 ( pg_stat_get_bgwriter_buf_written_clean PGNSP PGUID 12 1
31413143
DESCR("statistics: number of buffers written by the bgwriter for cleaning dirty buffers");
31423144
DATA(insert OID = 2773 ( pg_stat_get_bgwriter_maxwritten_clean PGNSP PGUID 12 1 0 0 f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_bgwriter_maxwritten_clean _null_ _null_ _null_ ));
31433145
DESCR("statistics: number of times the bgwriter stopped processing when it had written too many buffers while cleaning");
3146+
DATA(insert OID = 3075 ( pg_stat_get_bgwriter_stat_reset_time PGNSP PGUID 12 1 0 0 f f f t f s 0 0 1184 "" _null_ _null_ _null_ _null_ pg_stat_get_bgwriter_stat_reset_time _null_ _null_ _null_ ));
3147+
DESCR("statistics: last reset for the bgwriter");
31443148
DATA(insert OID = 2775 ( pg_stat_get_buf_written_backend PGNSP PGUID 12 1 0 0 f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_buf_written_backend _null_ _null_ _null_ ));
31453149
DESCR("statistics: number of buffers written by backends");
31463150
DATA(insert OID = 3063 ( pg_stat_get_buf_fsync_backend PGNSP PGUID 12 1 0 0 f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_buf_fsync_backend _null_ _null_ _null_ ));

src/include/pgstat.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,7 @@ typedef union PgStat_Msg
484484
* ------------------------------------------------------------
485485
*/
486486

487-
#define PGSTAT_FILE_FORMAT_ID 0x01A5BC98
487+
#define PGSTAT_FILE_FORMAT_ID 0x01A5BC99
488488

489489
/* ----------
490490
* PgStat_StatDBEntry The collector's data per database
@@ -508,6 +508,7 @@ typedef struct PgStat_StatDBEntry
508508
PgStat_Counter n_conflict_snapshot;
509509
PgStat_Counter n_conflict_bufferpin;
510510
PgStat_Counter n_conflict_startup_deadlock;
511+
TimestampTz stat_reset_timestamp;
511512

512513

513514
/*
@@ -584,6 +585,7 @@ typedef struct PgStat_GlobalStats
584585
PgStat_Counter buf_written_backend;
585586
PgStat_Counter buf_fsync_backend;
586587
PgStat_Counter buf_alloc;
588+
TimestampTz stat_reset_timestamp;
587589
} PgStat_GlobalStats;
588590

589591

src/test/regress/expected/rules.out

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,8 +1294,8 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
12941294
pg_stat_activity | SELECT s.datid, d.datname, s.procpid, s.usesysid, u.rolname AS usename, s.application_name, s.client_addr, s.client_port, s.backend_start, s.xact_start, s.query_start, s.waiting, s.current_query FROM pg_database d, pg_stat_get_activity(NULL::integer) s(datid, procpid, usesysid, application_name, current_query, waiting, xact_start, query_start, backend_start, client_addr, client_port), pg_authid u WHERE ((s.datid = d.oid) AND (s.usesysid = u.oid));
12951295
pg_stat_all_indexes | SELECT c.oid AS relid, i.oid AS indexrelid, n.nspname AS schemaname, c.relname, i.relname AS indexrelname, pg_stat_get_numscans(i.oid) AS idx_scan, pg_stat_get_tuples_returned(i.oid) AS idx_tup_read, pg_stat_get_tuples_fetched(i.oid) AS idx_tup_fetch 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))) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char"]));
12961296
pg_stat_all_tables | SELECT c.oid AS relid, n.nspname AS schemaname, c.relname, pg_stat_get_numscans(c.oid) AS seq_scan, pg_stat_get_tuples_returned(c.oid) AS seq_tup_read, (sum(pg_stat_get_numscans(i.indexrelid)))::bigint AS idx_scan, ((sum(pg_stat_get_tuples_fetched(i.indexrelid)))::bigint + pg_stat_get_tuples_fetched(c.oid)) AS idx_tup_fetch, pg_stat_get_tuples_inserted(c.oid) AS n_tup_ins, pg_stat_get_tuples_updated(c.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(c.oid) AS n_tup_del, pg_stat_get_tuples_hot_updated(c.oid) AS n_tup_hot_upd, 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_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, pg_stat_get_last_autoanalyze_time(c.oid) AS last_autoanalyze, 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 FROM ((pg_class c LEFT JOIN pg_index i ON ((c.oid = i.indrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char"])) GROUP BY c.oid, n.nspname, c.relname;
1297-
pg_stat_bgwriter | SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed, pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req, pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint, pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean, pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean, pg_stat_get_buf_written_backend() AS buffers_backend, pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync, pg_stat_get_buf_alloc() AS buffers_alloc;
1298-
pg_stat_database | SELECT d.oid AS datid, d.datname, pg_stat_get_db_numbackends(d.oid) AS numbackends, pg_stat_get_db_xact_commit(d.oid) AS xact_commit, pg_stat_get_db_xact_rollback(d.oid) AS xact_rollback, (pg_stat_get_db_blocks_fetched(d.oid) - pg_stat_get_db_blocks_hit(d.oid)) AS blks_read, pg_stat_get_db_blocks_hit(d.oid) AS blks_hit, pg_stat_get_db_tuples_returned(d.oid) AS tup_returned, pg_stat_get_db_tuples_fetched(d.oid) AS tup_fetched, pg_stat_get_db_tuples_inserted(d.oid) AS tup_inserted, pg_stat_get_db_tuples_updated(d.oid) AS tup_updated, pg_stat_get_db_tuples_deleted(d.oid) AS tup_deleted, pg_stat_get_db_conflict_all(d.oid) AS conflicts FROM pg_database d;
1297+
pg_stat_bgwriter | SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed, pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req, pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint, pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean, pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean, pg_stat_get_buf_written_backend() AS buffers_backend, pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync, pg_stat_get_buf_alloc() AS buffers_alloc, pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
1298+
pg_stat_database | SELECT d.oid AS datid, d.datname, pg_stat_get_db_numbackends(d.oid) AS numbackends, pg_stat_get_db_xact_commit(d.oid) AS xact_commit, pg_stat_get_db_xact_rollback(d.oid) AS xact_rollback, (pg_stat_get_db_blocks_fetched(d.oid) - pg_stat_get_db_blocks_hit(d.oid)) AS blks_read, pg_stat_get_db_blocks_hit(d.oid) AS blks_hit, pg_stat_get_db_tuples_returned(d.oid) AS tup_returned, pg_stat_get_db_tuples_fetched(d.oid) AS tup_fetched, pg_stat_get_db_tuples_inserted(d.oid) AS tup_inserted, pg_stat_get_db_tuples_updated(d.oid) AS tup_updated, pg_stat_get_db_tuples_deleted(d.oid) AS tup_deleted, pg_stat_get_db_conflict_all(d.oid) AS conflicts, pg_stat_get_db_stat_reset_time(d.oid) AS stats_reset FROM pg_database d;
12991299
pg_stat_database_conflicts | SELECT d.oid AS datid, d.datname, pg_stat_get_db_conflict_tablespace(d.oid) AS confl_tablespace, pg_stat_get_db_conflict_lock(d.oid) AS confl_lock, pg_stat_get_db_conflict_snapshot(d.oid) AS confl_snapshot, pg_stat_get_db_conflict_bufferpin(d.oid) AS confl_bufferpin, pg_stat_get_db_conflict_startup_deadlock(d.oid) AS confl_deadlock FROM pg_database d;
13001300
pg_stat_replication | SELECT s.procpid, s.usesysid, u.rolname AS usename, s.application_name, s.client_addr, s.client_port, s.backend_start, w.state, w.sent_location FROM pg_stat_get_activity(NULL::integer) s(datid, procpid, usesysid, application_name, current_query, waiting, xact_start, query_start, backend_start, client_addr, client_port), pg_authid u, pg_stat_get_wal_senders() w(procpid, state, sent_location) WHERE ((s.usesysid = u.oid) AND (s.procpid = w.procpid));
13011301
pg_stat_sys_indexes | SELECT pg_stat_all_indexes.relid, pg_stat_all_indexes.indexrelid, pg_stat_all_indexes.schemaname, pg_stat_all_indexes.relname, pg_stat_all_indexes.indexrelname, pg_stat_all_indexes.idx_scan, pg_stat_all_indexes.idx_tup_read, pg_stat_all_indexes.idx_tup_fetch FROM pg_stat_all_indexes WHERE ((pg_stat_all_indexes.schemaname = ANY (ARRAY['pg_catalog'::name, 'information_schema'::name])) OR (pg_stat_all_indexes.schemaname ~ '^pg_toast'::text));

0 commit comments

Comments
 (0)