diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml index 1d9509a2f6..646859decf 100644 --- a/doc/src/sgml/monitoring.sgml +++ b/doc/src/sgml/monitoring.sgml @@ -4385,6 +4385,16 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i + + + last_seq_scan timestamptz + + + The time of the last sequential scan of this table, based on the + most recent transaction stop time + + + seq_tup_read bigint @@ -4403,6 +4413,16 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i + + + last_idx_scan timestamptz + + + The time of the last index scan of this table, based on the + most recent transaction stop time + + + idx_tup_fetch bigint @@ -4654,6 +4674,16 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i + + + last_idx_scan timestamptz + + + The time of the last scan of this index, based on the + most recent transaction stop time + + + idx_tup_read bigint diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 50f092d7eb..3d79b2848f 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -871,9 +871,10 @@ GetCurrentStatementStartTimestamp(void) TimestampTz GetCurrentTransactionStopTimestamp(void) { - if (xactStopTimestamp != 0) - return xactStopTimestamp; - return GetCurrentTimestamp(); + if (xactStopTimestamp == 0) + xactStopTimestamp = GetCurrentTimestamp(); + + return xactStopTimestamp; } /* @@ -891,15 +892,6 @@ SetCurrentStatementStartTimestamp(void) Assert(stmtStartTimestamp != 0); } -/* - * SetCurrentTransactionStopTimestamp - */ -static inline void -SetCurrentTransactionStopTimestamp(void) -{ - xactStopTimestamp = GetCurrentTimestamp(); -} - /* * GetCurrentTransactionNestLevel * @@ -1396,9 +1388,7 @@ RecordTransactionCommit(void) START_CRIT_SECTION(); MyProc->delayChkptFlags |= DELAY_CHKPT_START; - SetCurrentTransactionStopTimestamp(); - - XactLogCommitRecord(xactStopTimestamp, + XactLogCommitRecord(GetCurrentTransactionStopTimestamp(), nchildren, children, nrels, rels, ndroppedstats, droppedstats, nmsgs, invalMessages, @@ -1422,7 +1412,7 @@ RecordTransactionCommit(void) */ if (!replorigin || replorigin_session_origin_timestamp == 0) - replorigin_session_origin_timestamp = xactStopTimestamp; + replorigin_session_origin_timestamp = GetCurrentTransactionStopTimestamp(); TransactionTreeSetCommitTsData(xid, nchildren, children, replorigin_session_origin_timestamp, @@ -1754,8 +1744,7 @@ RecordTransactionAbort(bool isSubXact) xact_time = GetCurrentTimestamp(); else { - SetCurrentTransactionStopTimestamp(); - xact_time = xactStopTimestamp; + xact_time = GetCurrentTransactionStopTimestamp(); } XactLogAbortRecord(xact_time, diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 5a844b63a1..801ba03ba4 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -657,8 +657,10 @@ CREATE VIEW pg_stat_all_tables AS N.nspname AS schemaname, C.relname AS relname, pg_stat_get_numscans(C.oid) AS seq_scan, + pg_stat_get_lastscan(C.oid) AS last_seq_scan, pg_stat_get_tuples_returned(C.oid) AS seq_tup_read, sum(pg_stat_get_numscans(I.indexrelid))::bigint AS idx_scan, + max(pg_stat_get_lastscan(I.indexrelid)) AS last_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, @@ -775,6 +777,7 @@ CREATE VIEW pg_stat_all_indexes AS C.relname AS relname, I.relname AS indexrelname, pg_stat_get_numscans(I.oid) AS idx_scan, + pg_stat_get_lastscan(I.oid) AS last_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 diff --git a/src/backend/utils/activity/pgstat_relation.c b/src/backend/utils/activity/pgstat_relation.c index a846d9ffb6..55a355f583 100644 --- a/src/backend/utils/activity/pgstat_relation.c +++ b/src/backend/utils/activity/pgstat_relation.c @@ -789,6 +789,12 @@ pgstat_relation_flush_cb(PgStat_EntryRef *entry_ref, bool nowait) tabentry = &shtabstats->stats; tabentry->numscans += lstats->t_counts.t_numscans; + if (lstats->t_counts.t_numscans) + { + TimestampTz t = GetCurrentTransactionStopTimestamp(); + if (t > tabentry->lastscan) + tabentry->lastscan = t; + } tabentry->tuples_returned += lstats->t_counts.t_tuples_returned; tabentry->tuples_fetched += lstats->t_counts.t_tuples_fetched; tabentry->tuples_inserted += lstats->t_counts.t_tuples_inserted; diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index be15b4b2e5..8c0237c496 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -52,6 +52,25 @@ pg_stat_get_numscans(PG_FUNCTION_ARGS) } +Datum +pg_stat_get_lastscan(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + TimestampTz result; + PgStat_StatTabEntry *tabentry; + + if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + result = 0; + else + result = tabentry->lastscan; + + if (result == 0) + PG_RETURN_NULL(); + else + PG_RETURN_TIMESTAMPTZ(result); +} + + Datum pg_stat_get_tuples_returned(PG_FUNCTION_ARGS) { diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index a07e737a33..d9a98e1c2e 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -5249,6 +5249,10 @@ proname => 'pg_stat_get_numscans', provolatile => 's', proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', prosrc => 'pg_stat_get_numscans' }, +{ oid => '2173', descr => 'statistics: time of the last scan for table/index', + proname => 'pg_stat_get_lastscan', provolatile => 's', proparallel => 'r', + prorettype => 'timestamptz', proargtypes => 'oid', + prosrc => 'pg_stat_get_lastscan' }, { oid => '1929', descr => 'statistics: number of tuples read by seqscan', proname => 'pg_stat_get_tuples_returned', provolatile => 's', proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', diff --git a/src/include/pgstat.h b/src/include/pgstat.h index ac28f813b4..597e2f238a 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -242,7 +242,7 @@ typedef struct PgStat_TableXactStatus * ------------------------------------------------------------ */ -#define PGSTAT_FILE_FORMAT_ID 0x01A5BCA7 +#define PGSTAT_FILE_FORMAT_ID 0x01A5BCA8 typedef struct PgStat_ArchiverStats { @@ -355,6 +355,7 @@ typedef struct PgStat_StatSubEntry typedef struct PgStat_StatTabEntry { PgStat_Counter numscans; + TimestampTz lastscan; PgStat_Counter tuples_returned; PgStat_Counter tuples_fetched; diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 7ec3d2688f..d9287ef0c9 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1768,6 +1768,7 @@ pg_stat_all_indexes| SELECT c.oid AS relid, c.relname, i.relname AS indexrelname, pg_stat_get_numscans(i.oid) AS idx_scan, + pg_stat_get_lastscan(i.oid) AS last_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 @@ -1779,8 +1780,10 @@ 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_lastscan(c.oid) AS last_seq_scan, pg_stat_get_tuples_returned(c.oid) AS seq_tup_read, (sum(pg_stat_get_numscans(i.indexrelid)))::bigint AS idx_scan, + max(pg_stat_get_lastscan(i.indexrelid)) AS last_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, @@ -2112,6 +2115,7 @@ pg_stat_sys_indexes| SELECT pg_stat_all_indexes.relid, pg_stat_all_indexes.relname, pg_stat_all_indexes.indexrelname, pg_stat_all_indexes.idx_scan, + pg_stat_all_indexes.last_idx_scan, pg_stat_all_indexes.idx_tup_read, pg_stat_all_indexes.idx_tup_fetch FROM pg_stat_all_indexes @@ -2120,8 +2124,10 @@ pg_stat_sys_tables| SELECT pg_stat_all_tables.relid, pg_stat_all_tables.schemaname, pg_stat_all_tables.relname, pg_stat_all_tables.seq_scan, + pg_stat_all_tables.last_seq_scan, pg_stat_all_tables.seq_tup_read, pg_stat_all_tables.idx_scan, + pg_stat_all_tables.last_idx_scan, pg_stat_all_tables.idx_tup_fetch, pg_stat_all_tables.n_tup_ins, pg_stat_all_tables.n_tup_upd, @@ -2156,6 +2162,7 @@ pg_stat_user_indexes| SELECT pg_stat_all_indexes.relid, pg_stat_all_indexes.relname, pg_stat_all_indexes.indexrelname, pg_stat_all_indexes.idx_scan, + pg_stat_all_indexes.last_idx_scan, pg_stat_all_indexes.idx_tup_read, pg_stat_all_indexes.idx_tup_fetch FROM pg_stat_all_indexes @@ -2164,8 +2171,10 @@ pg_stat_user_tables| SELECT pg_stat_all_tables.relid, pg_stat_all_tables.schemaname, pg_stat_all_tables.relname, pg_stat_all_tables.seq_scan, + pg_stat_all_tables.last_seq_scan, pg_stat_all_tables.seq_tup_read, pg_stat_all_tables.idx_scan, + pg_stat_all_tables.last_idx_scan, pg_stat_all_tables.idx_tup_fetch, pg_stat_all_tables.n_tup_ins, pg_stat_all_tables.n_tup_upd,