diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 099e9b6f4e9..32cb6fdbd76 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -5877,6 +5877,24 @@ description | Waiting for a newly initialized WAL file to reach durable storage
+
+
+
+ pg_stat_reset_single_index_counters
+
+ pg_stat_reset_single_index_counters ( oid )
+ void
+
+
+ Resets statistics for a single index in the current database
+ or shared across all databases in the cluster to zero.
+
+
+ This function is restricted to superusers by default, but other users
+ can be granted EXECUTE to run the function.
+
+
+
@@ -6022,7 +6040,7 @@ description | Waiting for a newly initialized WAL file to reach durable storage
void
- Resets statistics for a single table or index in the current database
+ Resets statistics for a single table in the current database
or shared across all databases in the cluster to zero.
It also resets statistics for a single sequence or materialized view
in the current database.
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 090281a03dd..8612d99a890 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -722,9 +722,9 @@ CREATE VIEW pg_stat_all_tables AS
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 +
+ sum(pg_stat_get_idx_numscans(I.indexrelid))::bigint AS idx_scan,
+ max(pg_stat_get_idx_lastscan(I.indexrelid)) AS last_idx_scan,
+ sum(pg_stat_get_idx_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,
@@ -761,8 +761,8 @@ CREATE VIEW pg_stat_xact_all_tables AS
C.relname AS relname,
pg_stat_get_xact_numscans(C.oid) AS seq_scan,
pg_stat_get_xact_tuples_returned(C.oid) AS seq_tup_read,
- sum(pg_stat_get_xact_numscans(I.indexrelid))::bigint AS idx_scan,
- sum(pg_stat_get_xact_tuples_fetched(I.indexrelid))::bigint +
+ sum(pg_stat_get_xact_idx_numscans(I.indexrelid))::bigint AS idx_scan,
+ sum(pg_stat_get_xact_idx_tuples_fetched(I.indexrelid))::bigint +
pg_stat_get_xact_tuples_fetched(C.oid) AS idx_tup_fetch,
pg_stat_get_xact_tuples_inserted(C.oid) AS n_tup_ins,
pg_stat_get_xact_tuples_updated(C.oid) AS n_tup_upd,
@@ -833,17 +833,17 @@ CREATE VIEW pg_statio_all_tables AS
pg_class T ON C.reltoastrelid = T.oid
LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
LEFT JOIN LATERAL (
- SELECT sum(pg_stat_get_blocks_fetched(indexrelid) -
- pg_stat_get_blocks_hit(indexrelid))::bigint
+ SELECT sum(pg_stat_get_idx_blocks_fetched(indexrelid) -
+ pg_stat_get_idx_blocks_hit(indexrelid))::bigint
AS idx_blks_read,
- sum(pg_stat_get_blocks_hit(indexrelid))::bigint
+ sum(pg_stat_get_idx_blocks_hit(indexrelid))::bigint
AS idx_blks_hit
FROM pg_index WHERE indrelid = C.oid ) I ON true
LEFT JOIN LATERAL (
- SELECT sum(pg_stat_get_blocks_fetched(indexrelid) -
- pg_stat_get_blocks_hit(indexrelid))::bigint
+ SELECT sum(pg_stat_get_idx_blocks_fetched(indexrelid) -
+ pg_stat_get_idx_blocks_hit(indexrelid))::bigint
AS idx_blks_read,
- sum(pg_stat_get_blocks_hit(indexrelid))::bigint
+ sum(pg_stat_get_idx_blocks_hit(indexrelid))::bigint
AS idx_blks_hit
FROM pg_index WHERE indrelid = T.oid ) X ON true
WHERE C.relkind IN ('r', 't', 'm');
@@ -865,11 +865,11 @@ CREATE VIEW pg_stat_all_indexes AS
N.nspname AS schemaname,
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,
- pg_stat_get_stat_reset_time(I.oid) AS stats_reset
+ pg_stat_get_idx_numscans(I.oid) AS idx_scan,
+ pg_stat_get_idx_lastscan(I.oid) AS last_idx_scan,
+ pg_stat_get_idx_tuples_returned(I.oid) AS idx_tup_read,
+ pg_stat_get_idx_tuples_fetched(I.oid) AS idx_tup_fetch,
+ pg_stat_get_idx_stat_reset_time(I.oid) AS stats_reset
FROM pg_class C JOIN
pg_index X ON C.oid = X.indrelid JOIN
pg_class I ON I.oid = X.indexrelid
@@ -893,10 +893,10 @@ CREATE VIEW pg_statio_all_indexes AS
N.nspname AS schemaname,
C.relname AS relname,
I.relname AS indexrelname,
- pg_stat_get_blocks_fetched(I.oid) -
- pg_stat_get_blocks_hit(I.oid) AS idx_blks_read,
- pg_stat_get_blocks_hit(I.oid) AS idx_blks_hit,
- pg_stat_get_stat_reset_time(I.oid) AS stats_reset
+ pg_stat_get_idx_blocks_fetched(I.oid) -
+ pg_stat_get_idx_blocks_hit(I.oid) AS idx_blks_read,
+ pg_stat_get_idx_blocks_hit(I.oid) AS idx_blks_hit,
+ pg_stat_get_idx_stat_reset_time(I.oid) AS stats_reset
FROM pg_class C JOIN
pg_index X ON C.oid = X.indrelid JOIN
pg_class I ON I.oid = X.indexrelid
diff --git a/src/backend/utils/activity/Makefile b/src/backend/utils/activity/Makefile
index 5fed953c28a..2e32d1485d6 100644
--- a/src/backend/utils/activity/Makefile
+++ b/src/backend/utils/activity/Makefile
@@ -25,6 +25,7 @@ OBJS = \
pgstat_checkpointer.o \
pgstat_database.o \
pgstat_function.o \
+ pgstat_index.o \
pgstat_io.o \
pgstat_kind.o \
pgstat_lock.o \
diff --git a/src/backend/utils/activity/meson.build b/src/backend/utils/activity/meson.build
index 470b5dac402..e6dcb2e26fc 100644
--- a/src/backend/utils/activity/meson.build
+++ b/src/backend/utils/activity/meson.build
@@ -10,6 +10,7 @@ backend_sources += files(
'pgstat_checkpointer.c',
'pgstat_database.c',
'pgstat_function.c',
+ 'pgstat_index.c',
'pgstat_io.c',
'pgstat_kind.c',
'pgstat_lock.c',
diff --git a/src/backend/utils/activity/pgstat.c b/src/backend/utils/activity/pgstat.c
index 50cd07822b4..fe1637e2095 100644
--- a/src/backend/utils/activity/pgstat.c
+++ b/src/backend/utils/activity/pgstat.c
@@ -317,6 +317,22 @@ static const PgStat_KindInfo pgstat_kind_builtin_infos[PGSTAT_KIND_BUILTIN_SIZE]
.reset_timestamp_cb = pgstat_relation_reset_timestamp_cb,
},
+ [PGSTAT_KIND_INDEX] = {
+ .name = "index",
+
+ .fixed_amount = false,
+ .write_to_file = true,
+
+ .shared_size = sizeof(PgStatShared_Index),
+ .shared_data_off = offsetof(PgStatShared_Index, stats),
+ .shared_data_len = sizeof(((PgStatShared_Index *) 0)->stats),
+ .pending_size = sizeof(PgStat_TableStatus),
+
+ .flush_pending_cb = pgstat_index_flush_cb,
+ .delete_pending_cb = pgstat_index_delete_pending_cb,
+ .reset_timestamp_cb = pgstat_index_reset_timestamp_cb,
+ },
+
[PGSTAT_KIND_FUNCTION] = {
.name = "function",
diff --git a/src/backend/utils/activity/pgstat_index.c b/src/backend/utils/activity/pgstat_index.c
new file mode 100644
index 00000000000..ce7a7f0f56c
--- /dev/null
+++ b/src/backend/utils/activity/pgstat_index.c
@@ -0,0 +1,131 @@
+/* -------------------------------------------------------------------------
+ *
+ * pgstat_index.c
+ * Implementation of index statistics.
+ *
+ * This file contains the implementation of index statistics.
+ *
+ * Copyright (c) 2001-2026, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/backend/utils/activity/pgstat_index.c
+ * -------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "access/xact.h"
+#include "catalog/catalog.h"
+#include "utils/memutils.h"
+#include "utils/pgstat_internal.h"
+#include "utils/rel.h"
+#include "utils/timestamp.h"
+
+
+/*
+ * Flush out pending stats for an index entry.
+ *
+ * If nowait is true and the lock could not be immediately acquired, returns
+ * false without flushing the entry. Otherwise returns true.
+ *
+ * Some of the stats are copied to the corresponding pending database stats
+ * entry when successfully flushing.
+ */
+bool
+pgstat_index_flush_cb(PgStat_EntryRef *entry_ref, bool nowait)
+{
+ Oid dboid;
+ PgStat_TableStatus *lstats; /* pending stats entry */
+ PgStatShared_Index *shidxstats;
+ PgStat_StatIdxEntry *idxentry; /* index entry of shared stats */
+ PgStat_StatDBEntry *dbentry; /* pending database entry */
+
+ dboid = entry_ref->shared_entry->key.dboid;
+ lstats = (PgStat_TableStatus *) entry_ref->pending;
+ shidxstats = (PgStatShared_Index *) entry_ref->shared_stats;
+
+ /*
+ * Ignore entries that didn't accumulate any actual counts, such as
+ * indexes that were opened by the planner but not used.
+ */
+ if (pg_memory_is_all_zeros(&lstats->counts,
+ sizeof(struct PgStat_TableCounts)))
+ return true;
+
+ if (!pgstat_lock_entry(entry_ref, nowait))
+ return false;
+
+ /* Add the values to the shared entry. */
+ idxentry = &shidxstats->stats;
+
+ idxentry->numscans += lstats->counts.numscans;
+ if (lstats->counts.numscans)
+ {
+ TimestampTz t = GetCurrentTransactionStopTimestamp();
+
+ if (t > idxentry->lastscan)
+ idxentry->lastscan = t;
+ }
+ idxentry->tuples_returned += lstats->counts.tuples_returned;
+ idxentry->tuples_fetched += lstats->counts.tuples_fetched;
+ idxentry->blocks_fetched += lstats->counts.blocks_fetched;
+ idxentry->blocks_hit += lstats->counts.blocks_hit;
+
+ pgstat_unlock_entry(entry_ref);
+
+ /* The entry was successfully flushed, add the same to database stats */
+ dbentry = pgstat_prep_database_pending(dboid);
+ dbentry->tuples_returned += lstats->counts.tuples_returned;
+ dbentry->tuples_fetched += lstats->counts.tuples_fetched;
+ dbentry->blocks_fetched += lstats->counts.blocks_fetched;
+ dbentry->blocks_hit += lstats->counts.blocks_hit;
+
+ return true;
+}
+
+/*
+ * Callback to delete pending index stats.
+ */
+void
+pgstat_index_delete_pending_cb(PgStat_EntryRef *entry_ref)
+{
+ PgStat_TableStatus *pending = (PgStat_TableStatus *) entry_ref->pending;
+
+ if (pending->relation)
+ pgstat_unlink_relation(pending->relation);
+}
+
+/*
+ * Callback to reset the timestamp on an index stats entry.
+ */
+void
+pgstat_index_reset_timestamp_cb(PgStatShared_Common *header, TimestampTz ts)
+{
+ ((PgStatShared_Index *) header)->stats.stat_reset_time = ts;
+}
+
+/*
+ * Support function for the SQL-callable pgstat* functions. Returns
+ * the collected statistics for one index or NULL. NULL doesn't mean
+ * that the index doesn't exist, just that there are no statistics, so the
+ * caller is better off to report ZERO instead.
+ */
+PgStat_StatIdxEntry *
+pgstat_fetch_stat_idxentry(Oid relid)
+{
+ return pgstat_fetch_stat_idxentry_ext(IsSharedRelation(relid), relid, NULL);
+}
+
+/*
+ * More efficient version of pgstat_fetch_stat_idxentry(), allowing to specify
+ * whether the to-be-accessed index is a shared relation or not. This version
+ * also returns whether the caller can pfree() the result if desired.
+ */
+PgStat_StatIdxEntry *
+pgstat_fetch_stat_idxentry_ext(bool shared, Oid reloid, bool *may_free)
+{
+ Oid dboid = (shared ? InvalidOid : MyDatabaseId);
+
+ return (PgStat_StatIdxEntry *)
+ pgstat_fetch_entry(PGSTAT_KIND_INDEX, dboid, reloid, may_free);
+}
diff --git a/src/backend/utils/activity/pgstat_relation.c b/src/backend/utils/activity/pgstat_relation.c
index 04f2eb21d0b..beea9188773 100644
--- a/src/backend/utils/activity/pgstat_relation.c
+++ b/src/backend/utils/activity/pgstat_relation.c
@@ -42,12 +42,24 @@ typedef struct TwoPhasePgStatRecord
} TwoPhasePgStatRecord;
-static PgStat_TableStatus *pgstat_prep_relation_pending(Oid rel_id, bool isshared);
+static PgStat_TableStatus *pgstat_prep_relation_pending(PgStat_Kind kind,
+ Oid rel_id, bool isshared);
static void add_tabstat_xact_level(PgStat_TableStatus *pgstat_info, int nest_level);
static void ensure_tabstat_xact_level(PgStat_TableStatus *pgstat_info);
static void save_truncdrop_counters(PgStat_TableXactStatus *trans, bool is_drop);
static void restore_truncdrop_counters(PgStat_TableXactStatus *trans);
+/*
+ * Determine the stats kind for a relation based on its relkind.
+ */
+static inline PgStat_Kind
+pgstat_get_relation_kind(char relkind)
+{
+ if (relkind == RELKIND_INDEX)
+ return PGSTAT_KIND_INDEX;
+ return PGSTAT_KIND_RELATION;
+}
+
/*
* Copy stats between relations. This is used for things like REINDEX
@@ -56,25 +68,52 @@ static void restore_truncdrop_counters(PgStat_TableXactStatus *trans);
void
pgstat_copy_relation_stats(Relation dst, Relation src)
{
- PgStat_StatTabEntry *srcstats;
- PgStatShared_Relation *dstshstats;
- PgStat_EntryRef *dst_ref;
+ PgStat_Kind kind = pgstat_get_relation_kind(src->rd_rel->relkind);
- srcstats = pgstat_fetch_stat_tabentry_ext(src->rd_rel->relisshared,
- RelationGetRelid(src),
- NULL);
- if (!srcstats)
- return;
+ if (kind == PGSTAT_KIND_INDEX)
+ {
+ PgStat_StatIdxEntry *srcstats;
+ PgStatShared_Index *dstshstats;
+ PgStat_EntryRef *dst_ref;
- dst_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_RELATION,
- dst->rd_rel->relisshared ? InvalidOid : MyDatabaseId,
- RelationGetRelid(dst),
- false);
+ srcstats = pgstat_fetch_stat_idxentry_ext(src->rd_rel->relisshared,
+ RelationGetRelid(src),
+ NULL);
+ if (!srcstats)
+ return;
- dstshstats = (PgStatShared_Relation *) dst_ref->shared_stats;
- dstshstats->stats = *srcstats;
+ dst_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_INDEX,
+ dst->rd_rel->relisshared ? InvalidOid : MyDatabaseId,
+ RelationGetRelid(dst),
+ false);
- pgstat_unlock_entry(dst_ref);
+ dstshstats = (PgStatShared_Index *) dst_ref->shared_stats;
+ dstshstats->stats = *srcstats;
+
+ pgstat_unlock_entry(dst_ref);
+ }
+ else
+ {
+ PgStat_StatTabEntry *srcstats;
+ PgStatShared_Relation *dstshstats;
+ PgStat_EntryRef *dst_ref;
+
+ srcstats = pgstat_fetch_stat_tabentry_ext(src->rd_rel->relisshared,
+ RelationGetRelid(src),
+ NULL);
+ if (!srcstats)
+ return;
+
+ dst_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_RELATION,
+ dst->rd_rel->relisshared ? InvalidOid : MyDatabaseId,
+ RelationGetRelid(dst),
+ false);
+
+ dstshstats = (PgStatShared_Relation *) dst_ref->shared_stats;
+ dstshstats->stats = *srcstats;
+
+ pgstat_unlock_entry(dst_ref);
+ }
}
/*
@@ -131,11 +170,16 @@ pgstat_init_relation(Relation rel)
void
pgstat_assoc_relation(Relation rel)
{
+ PgStat_Kind kind;
+
Assert(rel->pgstat_enabled);
Assert(rel->pgstat_info == NULL);
+ kind = pgstat_get_relation_kind(rel->rd_rel->relkind);
+
/* find or make the PgStat_TableStatus entry, and update link */
- rel->pgstat_info = pgstat_prep_relation_pending(RelationGetRelid(rel),
+ rel->pgstat_info = pgstat_prep_relation_pending(kind,
+ RelationGetRelid(rel),
rel->rd_rel->relisshared);
/* don't allow link a stats to multiple relcache entries */
@@ -168,7 +212,9 @@ pgstat_unlink_relation(Relation rel)
void
pgstat_create_relation(Relation rel)
{
- pgstat_create_transactional(PGSTAT_KIND_RELATION,
+ PgStat_Kind kind = pgstat_get_relation_kind(rel->rd_rel->relkind);
+
+ pgstat_create_transactional(kind,
rel->rd_rel->relisshared ? InvalidOid : MyDatabaseId,
RelationGetRelid(rel));
}
@@ -181,8 +227,9 @@ pgstat_drop_relation(Relation rel)
{
int nest_level = GetCurrentTransactionNestLevel();
PgStat_TableStatus *pgstat_info;
+ PgStat_Kind kind = pgstat_get_relation_kind(rel->rd_rel->relkind);
- pgstat_drop_transactional(PGSTAT_KIND_RELATION,
+ pgstat_drop_transactional(kind,
rel->rd_rel->relisshared ? InvalidOid : MyDatabaseId,
RelationGetRelid(rel));
@@ -500,16 +547,25 @@ pgstat_fetch_stat_tabentry_ext(bool shared, Oid reloid, bool *may_free)
*/
PgStat_TableStatus *
find_tabstat_entry(Oid rel_id)
+{
+ return find_tabstat_entry_kind(PGSTAT_KIND_RELATION, rel_id);
+}
+
+/*
+ * Same as find_tabstat_entry but for a specific stats kind.
+ */
+PgStat_TableStatus *
+find_tabstat_entry_kind(PgStat_Kind kind, Oid rel_id)
{
PgStat_EntryRef *entry_ref;
PgStat_TableXactStatus *trans;
PgStat_TableStatus *tabentry = NULL;
PgStat_TableStatus *tablestatus = NULL;
- entry_ref = pgstat_fetch_pending_entry(PGSTAT_KIND_RELATION, MyDatabaseId, rel_id);
+ entry_ref = pgstat_fetch_pending_entry(kind, MyDatabaseId, rel_id);
if (!entry_ref)
{
- entry_ref = pgstat_fetch_pending_entry(PGSTAT_KIND_RELATION, InvalidOid, rel_id);
+ entry_ref = pgstat_fetch_pending_entry(kind, InvalidOid, rel_id);
if (!entry_ref)
return tablestatus;
}
@@ -752,7 +808,7 @@ pgstat_twophase_postcommit(FullTransactionId fxid, uint16 info,
PgStat_TableStatus *pgstat_info;
/* Find or create a tabstat entry for the rel */
- pgstat_info = pgstat_prep_relation_pending(rec->id, rec->shared);
+ pgstat_info = pgstat_prep_relation_pending(PGSTAT_KIND_RELATION, rec->id, rec->shared);
/* Same math as in AtEOXact_PgStat, commit case */
pgstat_info->counts.tuples_inserted += rec->tuples_inserted;
@@ -788,7 +844,7 @@ pgstat_twophase_postabort(FullTransactionId fxid, uint16 info,
PgStat_TableStatus *pgstat_info;
/* Find or create a tabstat entry for the rel */
- pgstat_info = pgstat_prep_relation_pending(rec->id, rec->shared);
+ pgstat_info = pgstat_prep_relation_pending(PGSTAT_KIND_RELATION, rec->id, rec->shared);
/* Same math as in AtEOXact_PgStat, abort case */
if (rec->truncdropped)
@@ -826,10 +882,7 @@ pgstat_relation_flush_cb(PgStat_EntryRef *entry_ref, bool nowait)
lstats = (PgStat_TableStatus *) entry_ref->pending;
shtabstats = (PgStatShared_Relation *) entry_ref->shared_stats;
- /*
- * Ignore entries that didn't accumulate any actual counts, such as
- * indexes that were opened by the planner but not used.
- */
+ /* ignore entries that didn't accumulate any actual counts */
if (pg_memory_is_all_zeros(&lstats->counts,
sizeof(struct PgStat_TableCounts)))
return true;
@@ -922,12 +975,12 @@ pgstat_relation_reset_timestamp_cb(PgStatShared_Common *header, TimestampTz ts)
* initialized if not exists.
*/
static PgStat_TableStatus *
-pgstat_prep_relation_pending(Oid rel_id, bool isshared)
+pgstat_prep_relation_pending(PgStat_Kind kind, Oid rel_id, bool isshared)
{
PgStat_EntryRef *entry_ref;
PgStat_TableStatus *pending;
- entry_ref = pgstat_prep_pending_entry(PGSTAT_KIND_RELATION,
+ entry_ref = pgstat_prep_pending_entry(kind,
isshared ? InvalidOid : MyDatabaseId,
rel_id, NULL);
pending = entry_ref->pending;
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 565d0e70768..946025f39ed 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -108,6 +108,40 @@ PG_STAT_GET_RELENTRY_INT64(tuples_updated)
/* pg_stat_get_vacuum_count */
PG_STAT_GET_RELENTRY_INT64(vacuum_count)
+/*
+ * Accessor macro for index stats entries (PgStat_StatIdxEntry).
+ */
+#define PG_STAT_GET_IDXENTRY_INT64(stat) \
+Datum \
+CppConcat(pg_stat_get_idx_,stat)(PG_FUNCTION_ARGS) \
+{ \
+ Oid relid = PG_GETARG_OID(0); \
+ int64 result; \
+ PgStat_StatIdxEntry *idxentry; \
+ \
+ if ((idxentry = pgstat_fetch_stat_idxentry(relid)) == NULL) \
+ result = 0; \
+ else \
+ result = (int64) (idxentry->stat); \
+ \
+ PG_RETURN_INT64(result); \
+}
+
+/* pg_stat_get_idx_numscans */
+PG_STAT_GET_IDXENTRY_INT64(numscans)
+
+/* pg_stat_get_idx_tuples_returned */
+PG_STAT_GET_IDXENTRY_INT64(tuples_returned)
+
+/* pg_stat_get_idx_tuples_fetched */
+PG_STAT_GET_IDXENTRY_INT64(tuples_fetched)
+
+/* pg_stat_get_idx_blocks_fetched */
+PG_STAT_GET_IDXENTRY_INT64(blocks_fetched)
+
+/* pg_stat_get_idx_blocks_hit */
+PG_STAT_GET_IDXENTRY_INT64(blocks_hit)
+
#define PG_STAT_GET_RELENTRY_FLOAT8(stat) \
Datum \
CppConcat(pg_stat_get_,stat)(PG_FUNCTION_ARGS) \
@@ -173,6 +207,34 @@ PG_STAT_GET_RELENTRY_TIMESTAMPTZ(lastscan)
/* pg_stat_get_stat_reset_time */
PG_STAT_GET_RELENTRY_TIMESTAMPTZ(stat_reset_time)
+/*
+ * Accessor macro for index timestamp fields.
+ */
+#define PG_STAT_GET_IDXENTRY_TIMESTAMPTZ(stat) \
+Datum \
+CppConcat(pg_stat_get_idx_,stat)(PG_FUNCTION_ARGS) \
+{ \
+ Oid relid = PG_GETARG_OID(0); \
+ TimestampTz result; \
+ PgStat_StatIdxEntry *idxentry; \
+ \
+ if ((idxentry = pgstat_fetch_stat_idxentry(relid)) == NULL) \
+ result = 0; \
+ else \
+ result = idxentry->stat; \
+ \
+ if (result == 0) \
+ PG_RETURN_NULL(); \
+ else \
+ PG_RETURN_TIMESTAMPTZ(result); \
+}
+
+/* pg_stat_get_idx_lastscan */
+PG_STAT_GET_IDXENTRY_TIMESTAMPTZ(lastscan)
+
+/* pg_stat_get_idx_stat_reset_time */
+PG_STAT_GET_IDXENTRY_TIMESTAMPTZ(stat_reset_time)
+
Datum
pg_stat_get_function_calls(PG_FUNCTION_ARGS)
{
@@ -1906,6 +1968,41 @@ PG_STAT_GET_XACT_RELENTRY_INT64(tuples_updated)
/* pg_stat_get_xact_tuples_deleted */
PG_STAT_GET_XACT_RELENTRY_INT64(tuples_deleted)
+/*
+ * Accessor macro for in-transaction index stats.
+ */
+#define PG_STAT_GET_XACT_IDXENTRY_INT64(stat) \
+Datum \
+CppConcat(pg_stat_get_xact_idx_,stat)(PG_FUNCTION_ARGS) \
+{ \
+ Oid relid = PG_GETARG_OID(0); \
+ int64 result; \
+ PgStat_TableStatus *tabentry; \
+ \
+ tabentry = find_tabstat_entry_kind(PGSTAT_KIND_INDEX, relid); \
+ if (!tabentry) \
+ result = 0; \
+ else \
+ result = (int64) (tabentry->counts.stat); \
+ \
+ PG_RETURN_INT64(result); \
+}
+
+/* pg_stat_get_xact_idx_numscans */
+PG_STAT_GET_XACT_IDXENTRY_INT64(numscans)
+
+/* pg_stat_get_xact_idx_tuples_returned */
+PG_STAT_GET_XACT_IDXENTRY_INT64(tuples_returned)
+
+/* pg_stat_get_xact_idx_tuples_fetched */
+PG_STAT_GET_XACT_IDXENTRY_INT64(tuples_fetched)
+
+/* pg_stat_get_xact_idx_blocks_fetched */
+PG_STAT_GET_XACT_IDXENTRY_INT64(blocks_fetched)
+
+/* pg_stat_get_xact_idx_blocks_hit */
+PG_STAT_GET_XACT_IDXENTRY_INT64(blocks_hit)
+
Datum
pg_stat_get_xact_function_calls(PG_FUNCTION_ARGS)
{
@@ -2047,6 +2144,17 @@ pg_stat_reset_single_table_counters(PG_FUNCTION_ARGS)
PG_RETURN_VOID();
}
+Datum
+pg_stat_reset_single_index_counters(PG_FUNCTION_ARGS)
+{
+ Oid idxoid = PG_GETARG_OID(0);
+ Oid dboid = (IsSharedRelation(idxoid) ? InvalidOid : MyDatabaseId);
+
+ pgstat_reset(PGSTAT_KIND_INDEX, dboid, idxoid);
+
+ PG_RETURN_VOID();
+}
+
Datum
pg_stat_reset_single_function_counters(PG_FUNCTION_ARGS)
{
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index f20ea73ed39..93132521532 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -57,6 +57,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 202607273
+#define CATALOG_VERSION_NO 202608121
#endif
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index f8a021987b5..66c3c9a04cf 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5555,11 +5555,11 @@
proargnames => '{mcv_list,index,values,nulls,frequency,base_frequency}',
prosrc => 'pg_stats_ext_mcvlist_items' },
-{ oid => '1928', descr => 'statistics: number of scans done for table/index',
+{ oid => '1928', descr => 'statistics: number of scans done for table',
proname => 'pg_stat_get_numscans', provolatile => 's', proparallel => 'r',
prorettype => 'int8', proargtypes => 'oid',
prosrc => 'pg_stat_get_numscans' },
-{ oid => '6310', descr => 'statistics: time of the last scan for table/index',
+{ oid => '6310', descr => 'statistics: time of the last scan for table',
proname => 'pg_stat_get_lastscan', provolatile => 's', proparallel => 'r',
prorettype => 'timestamptz', proargtypes => 'oid',
prosrc => 'pg_stat_get_lastscan' },
@@ -6142,7 +6142,7 @@
prosrc => 'pg_stat_get_function_stat_reset_time' },
{ oid => '3037',
- descr => 'statistics: number of scans done for table/index in current transaction',
+ descr => 'statistics: number of scans done for table in current transaction',
proname => 'pg_stat_get_xact_numscans', provolatile => 'v',
proparallel => 'r', prorettype => 'int8', proargtypes => 'oid',
prosrc => 'pg_stat_get_xact_numscans' },
@@ -6234,10 +6234,71 @@
proargdefaults => '{NULL}', prosrc => 'pg_stat_reset_shared',
proacl => '{POSTGRES=X}' },
{ oid => '3776',
- descr => 'statistics: reset collected statistics for a single table or index in the current database or shared across all databases in the cluster',
+ descr => 'statistics: reset collected statistics for a single table in the current database or shared across all databases in the cluster',
proname => 'pg_stat_reset_single_table_counters', provolatile => 'v',
prorettype => 'void', proargtypes => 'oid',
prosrc => 'pg_stat_reset_single_table_counters', proacl => '{POSTGRES=X}' },
+{ oid => '8450',
+ descr => 'statistics: reset collected statistics for a single index in the current database or shared across all databases in the cluster',
+ proname => 'pg_stat_reset_single_index_counters', provolatile => 'v',
+ prorettype => 'void', proargtypes => 'oid',
+ prosrc => 'pg_stat_reset_single_index_counters', proacl => '{POSTGRES=X}' },
+{ oid => '8451', descr => 'statistics: number of scans done for index',
+ proname => 'pg_stat_get_idx_numscans', provolatile => 's', proparallel => 'r',
+ prorettype => 'int8', proargtypes => 'oid',
+ prosrc => 'pg_stat_get_idx_numscans' },
+{ oid => '8452',
+ descr => 'statistics: number of index entries returned by index',
+ proname => 'pg_stat_get_idx_tuples_returned', provolatile => 's',
+ proparallel => 'r', prorettype => 'int8', proargtypes => 'oid',
+ prosrc => 'pg_stat_get_idx_tuples_returned' },
+{ oid => '8453',
+ descr => 'statistics: number of tuples fetched from table by index',
+ proname => 'pg_stat_get_idx_tuples_fetched', provolatile => 's',
+ proparallel => 'r', prorettype => 'int8', proargtypes => 'oid',
+ prosrc => 'pg_stat_get_idx_tuples_fetched' },
+{ oid => '8454', descr => 'statistics: number of blocks fetched for index',
+ proname => 'pg_stat_get_idx_blocks_fetched', provolatile => 's',
+ proparallel => 'r', prorettype => 'int8', proargtypes => 'oid',
+ prosrc => 'pg_stat_get_idx_blocks_fetched' },
+{ oid => '8455',
+ descr => 'statistics: number of blocks found in cache for index',
+ proname => 'pg_stat_get_idx_blocks_hit', provolatile => 's',
+ proparallel => 'r', prorettype => 'int8', proargtypes => 'oid',
+ prosrc => 'pg_stat_get_idx_blocks_hit' },
+{ oid => '8456', descr => 'statistics: time of the last scan for index',
+ proname => 'pg_stat_get_idx_lastscan', provolatile => 's', proparallel => 'r',
+ prorettype => 'timestamptz', proargtypes => 'oid',
+ prosrc => 'pg_stat_get_idx_lastscan' },
+{ oid => '8457', descr => 'statistics: last reset for an index',
+ proname => 'pg_stat_get_idx_stat_reset_time', provolatile => 's',
+ proparallel => 'r', prorettype => 'timestamptz', proargtypes => 'oid',
+ prosrc => 'pg_stat_get_idx_stat_reset_time' },
+{ oid => '8458',
+ descr => 'statistics: number of scans done for index in current transaction',
+ proname => 'pg_stat_get_xact_idx_numscans', provolatile => 'v',
+ proparallel => 'r', prorettype => 'int8', proargtypes => 'oid',
+ prosrc => 'pg_stat_get_xact_idx_numscans' },
+{ oid => '8459',
+ descr => 'statistics: number of index entries returned in current transaction',
+ proname => 'pg_stat_get_xact_idx_tuples_returned', provolatile => 'v',
+ proparallel => 'r', prorettype => 'int8', proargtypes => 'oid',
+ prosrc => 'pg_stat_get_xact_idx_tuples_returned' },
+{ oid => '8460',
+ descr => 'statistics: number of tuples fetched by index in current transaction',
+ proname => 'pg_stat_get_xact_idx_tuples_fetched', provolatile => 'v',
+ proparallel => 'r', prorettype => 'int8', proargtypes => 'oid',
+ prosrc => 'pg_stat_get_xact_idx_tuples_fetched' },
+{ oid => '8461',
+ descr => 'statistics: number of blocks fetched for index in current transaction',
+ proname => 'pg_stat_get_xact_idx_blocks_fetched', provolatile => 'v',
+ proparallel => 'r', prorettype => 'int8', proargtypes => 'oid',
+ prosrc => 'pg_stat_get_xact_idx_blocks_fetched' },
+{ oid => '8462',
+ descr => 'statistics: number of blocks found in cache for index in current transaction',
+ proname => 'pg_stat_get_xact_idx_blocks_hit', provolatile => 'v',
+ proparallel => 'r', prorettype => 'int8', proargtypes => 'oid',
+ prosrc => 'pg_stat_get_xact_idx_blocks_hit' },
{ oid => '3777',
descr => 'statistics: reset collected statistics for a single function in the current database',
proname => 'pg_stat_reset_single_function_counters', provolatile => 'v',
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 58a44857f13..9c29dbe2c44 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -218,7 +218,7 @@ typedef struct PgStat_TableXactStatus
* ------------------------------------------------------------
*/
-#define PGSTAT_FILE_FORMAT_ID 0x01A5BCBC
+#define PGSTAT_FILE_FORMAT_ID 0x01A5BCBD
typedef struct PgStat_ArchiverStats
{
@@ -487,6 +487,20 @@ typedef struct PgStat_StatTabEntry
TimestampTz stat_reset_time;
} PgStat_StatTabEntry;
+typedef struct PgStat_StatIdxEntry
+{
+ PgStat_Counter numscans;
+ TimestampTz lastscan;
+
+ PgStat_Counter tuples_returned;
+ PgStat_Counter tuples_fetched;
+
+ PgStat_Counter blocks_fetched;
+ PgStat_Counter blocks_hit;
+
+ TimestampTz stat_reset_time;
+} PgStat_StatIdxEntry;
+
/* ------
* PgStat_WalCounters WAL activity data gathered from WalUsage
*
@@ -779,6 +793,12 @@ extern PgStat_StatTabEntry *pgstat_fetch_stat_tabentry_ext(bool shared,
Oid reloid,
bool *may_free);
extern PgStat_TableStatus *find_tabstat_entry(Oid rel_id);
+extern PgStat_TableStatus *find_tabstat_entry_kind(PgStat_Kind kind, Oid rel_id);
+
+extern PgStat_StatIdxEntry *pgstat_fetch_stat_idxentry(Oid relid);
+extern PgStat_StatIdxEntry *pgstat_fetch_stat_idxentry_ext(bool shared,
+ Oid reloid,
+ bool *may_free);
/*
diff --git a/src/include/utils/pgstat_internal.h b/src/include/utils/pgstat_internal.h
index b0a17691966..1ef98620e1c 100644
--- a/src/include/utils/pgstat_internal.h
+++ b/src/include/utils/pgstat_internal.h
@@ -508,6 +508,12 @@ typedef struct PgStatShared_Relation
PgStat_StatTabEntry stats;
} PgStatShared_Relation;
+typedef struct PgStatShared_Index
+{
+ PgStatShared_Common header;
+ PgStat_StatIdxEntry stats;
+} PgStatShared_Index;
+
typedef struct PgStatShared_Function
{
PgStatShared_Common header;
@@ -789,6 +795,15 @@ extern void pgstat_relation_delete_pending_cb(PgStat_EntryRef *entry_ref);
extern void pgstat_relation_reset_timestamp_cb(PgStatShared_Common *header, TimestampTz ts);
+/*
+ * Functions in pgstat_index.c
+ */
+
+extern bool pgstat_index_flush_cb(PgStat_EntryRef *entry_ref, bool nowait);
+extern void pgstat_index_delete_pending_cb(PgStat_EntryRef *entry_ref);
+extern void pgstat_index_reset_timestamp_cb(PgStatShared_Common *header, TimestampTz ts);
+
+
/*
* Functions in pgstat_replslot.c
*/
diff --git a/src/include/utils/pgstat_kind.h b/src/include/utils/pgstat_kind.h
index 2d78a029683..45ca599d0dd 100644
--- a/src/include/utils/pgstat_kind.h
+++ b/src/include/utils/pgstat_kind.h
@@ -26,19 +26,20 @@
/* stats for variable-numbered objects */
#define PGSTAT_KIND_DATABASE 1 /* database-wide statistics */
#define PGSTAT_KIND_RELATION 2 /* per-table statistics */
-#define PGSTAT_KIND_FUNCTION 3 /* per-function statistics */
-#define PGSTAT_KIND_REPLSLOT 4 /* per-slot statistics */
-#define PGSTAT_KIND_SUBSCRIPTION 5 /* per-subscription statistics */
-#define PGSTAT_KIND_BACKEND 6 /* per-backend statistics */
+#define PGSTAT_KIND_INDEX 3 /* per-index statistics */
+#define PGSTAT_KIND_FUNCTION 4 /* per-function statistics */
+#define PGSTAT_KIND_REPLSLOT 5 /* per-slot statistics */
+#define PGSTAT_KIND_SUBSCRIPTION 6 /* per-subscription statistics */
+#define PGSTAT_KIND_BACKEND 7 /* per-backend statistics */
/* stats for fixed-numbered objects */
-#define PGSTAT_KIND_ARCHIVER 7
-#define PGSTAT_KIND_BGWRITER 8
-#define PGSTAT_KIND_CHECKPOINTER 9
-#define PGSTAT_KIND_IO 10
-#define PGSTAT_KIND_LOCK 11
-#define PGSTAT_KIND_SLRU 12
-#define PGSTAT_KIND_WAL 13
+#define PGSTAT_KIND_ARCHIVER 8
+#define PGSTAT_KIND_BGWRITER 9
+#define PGSTAT_KIND_CHECKPOINTER 10
+#define PGSTAT_KIND_IO 11
+#define PGSTAT_KIND_LOCK 12
+#define PGSTAT_KIND_SLRU 13
+#define PGSTAT_KIND_WAL 14
#define PGSTAT_KIND_BUILTIN_MIN PGSTAT_KIND_DATABASE
#define PGSTAT_KIND_BUILTIN_MAX PGSTAT_KIND_WAL
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 6a3341356da..1a29d46213e 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1806,11 +1806,11 @@ pg_stat_all_indexes| SELECT c.oid AS relid,
n.nspname AS schemaname,
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,
- pg_stat_get_stat_reset_time(i.oid) AS stats_reset
+ pg_stat_get_idx_numscans(i.oid) AS idx_scan,
+ pg_stat_get_idx_lastscan(i.oid) AS last_idx_scan,
+ pg_stat_get_idx_tuples_returned(i.oid) AS idx_tup_read,
+ pg_stat_get_idx_tuples_fetched(i.oid) AS idx_tup_fetch,
+ pg_stat_get_idx_stat_reset_time(i.oid) AS stats_reset
FROM (((pg_class c
JOIN pg_index x ON ((c.oid = x.indrelid)))
JOIN pg_class i ON ((i.oid = x.indexrelid)))
@@ -1822,9 +1822,9 @@ pg_stat_all_tables| SELECT c.oid AS relid,
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,
+ (sum(pg_stat_get_idx_numscans(i.indexrelid)))::bigint AS idx_scan,
+ max(pg_stat_get_idx_lastscan(i.indexrelid)) AS last_idx_scan,
+ ((sum(pg_stat_get_idx_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,
@@ -2455,8 +2455,8 @@ pg_stat_xact_all_tables| SELECT c.oid AS relid,
c.relname,
pg_stat_get_xact_numscans(c.oid) AS seq_scan,
pg_stat_get_xact_tuples_returned(c.oid) AS seq_tup_read,
- (sum(pg_stat_get_xact_numscans(i.indexrelid)))::bigint AS idx_scan,
- ((sum(pg_stat_get_xact_tuples_fetched(i.indexrelid)))::bigint + pg_stat_get_xact_tuples_fetched(c.oid)) AS idx_tup_fetch,
+ (sum(pg_stat_get_xact_idx_numscans(i.indexrelid)))::bigint AS idx_scan,
+ ((sum(pg_stat_get_xact_idx_tuples_fetched(i.indexrelid)))::bigint + pg_stat_get_xact_tuples_fetched(c.oid)) AS idx_tup_fetch,
pg_stat_get_xact_tuples_inserted(c.oid) AS n_tup_ins,
pg_stat_get_xact_tuples_updated(c.oid) AS n_tup_upd,
pg_stat_get_xact_tuples_deleted(c.oid) AS n_tup_del,
@@ -2509,9 +2509,9 @@ pg_statio_all_indexes| SELECT c.oid AS relid,
n.nspname AS schemaname,
c.relname,
i.relname AS indexrelname,
- (pg_stat_get_blocks_fetched(i.oid) - pg_stat_get_blocks_hit(i.oid)) AS idx_blks_read,
- pg_stat_get_blocks_hit(i.oid) AS idx_blks_hit,
- pg_stat_get_stat_reset_time(i.oid) AS stats_reset
+ (pg_stat_get_idx_blocks_fetched(i.oid) - pg_stat_get_idx_blocks_hit(i.oid)) AS idx_blks_read,
+ pg_stat_get_idx_blocks_hit(i.oid) AS idx_blks_hit,
+ pg_stat_get_idx_stat_reset_time(i.oid) AS stats_reset
FROM (((pg_class c
JOIN pg_index x ON ((c.oid = x.indrelid)))
JOIN pg_class i ON ((i.oid = x.indexrelid)))
@@ -2541,12 +2541,12 @@ pg_statio_all_tables| SELECT c.oid AS relid,
FROM ((((pg_class c
LEFT JOIN pg_class t ON ((c.reltoastrelid = t.oid)))
LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace)))
- LEFT JOIN LATERAL ( SELECT (sum((pg_stat_get_blocks_fetched(pg_index.indexrelid) - pg_stat_get_blocks_hit(pg_index.indexrelid))))::bigint AS idx_blks_read,
- (sum(pg_stat_get_blocks_hit(pg_index.indexrelid)))::bigint AS idx_blks_hit
+ LEFT JOIN LATERAL ( SELECT (sum((pg_stat_get_idx_blocks_fetched(pg_index.indexrelid) - pg_stat_get_idx_blocks_hit(pg_index.indexrelid))))::bigint AS idx_blks_read,
+ (sum(pg_stat_get_idx_blocks_hit(pg_index.indexrelid)))::bigint AS idx_blks_hit
FROM pg_index
WHERE (pg_index.indrelid = c.oid)) i ON (true))
- LEFT JOIN LATERAL ( SELECT (sum((pg_stat_get_blocks_fetched(pg_index.indexrelid) - pg_stat_get_blocks_hit(pg_index.indexrelid))))::bigint AS idx_blks_read,
- (sum(pg_stat_get_blocks_hit(pg_index.indexrelid)))::bigint AS idx_blks_hit
+ LEFT JOIN LATERAL ( SELECT (sum((pg_stat_get_idx_blocks_fetched(pg_index.indexrelid) - pg_stat_get_idx_blocks_hit(pg_index.indexrelid))))::bigint AS idx_blks_read,
+ (sum(pg_stat_get_idx_blocks_hit(pg_index.indexrelid)))::bigint AS idx_blks_hit
FROM pg_index
WHERE (pg_index.indrelid = t.oid)) x ON (true))
WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char", 'm'::"char"]));
diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out
index e230356de13..c682a9ed60a 100644
--- a/src/test/regress/expected/stats.out
+++ b/src/test/regress/expected/stats.out
@@ -116,18 +116,19 @@ SELECT id, name, fixed_amount,
----+--------------+--------------+-----------+---------------
1 | database | f | t | t
2 | relation | f | f | t
- 3 | function | f | f | t
- 4 | replslot | f | t | t
- 5 | subscription | f | t | t
- 6 | backend | f | t | f
- 7 | archiver | t | f | t
- 8 | bgwriter | t | f | t
- 9 | checkpointer | t | f | t
- 10 | io | t | f | t
- 11 | lock | t | f | t
- 12 | slru | t | f | t
- 13 | wal | t | f | t
-(13 rows)
+ 3 | index | f | f | t
+ 4 | function | f | f | t
+ 5 | replslot | f | t | t
+ 6 | subscription | f | t | t
+ 7 | backend | f | t | f
+ 8 | archiver | t | f | t
+ 9 | bgwriter | t | f | t
+ 10 | checkpointer | t | f | t
+ 11 | io | t | f | t
+ 12 | lock | t | f | t
+ 13 | slru | t | f | t
+ 14 | wal | t | f | t
+(14 rows)
-- ensure that both seqscan and indexscan plans are allowed
SET enable_seqscan TO on;
@@ -900,8 +901,8 @@ SELECT idx_scan, :'test_last_idx' < last_idx_scan AS idx_ok,
(1 row)
-- check that the stats in pg_stat_all_indexes are reset
-SELECT pg_stat_reset_single_table_counters('test_last_scan_pkey'::regclass);
- pg_stat_reset_single_table_counters
+SELECT pg_stat_reset_single_index_counters('test_last_scan_pkey'::regclass);
+ pg_stat_reset_single_index_counters
-------------------------------------
(1 row)
@@ -1385,21 +1386,21 @@ select a from stats_test_tab1 where a = 3;
3
(1 row)
-SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
+SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid);
pg_stat_have_stats
--------------------
t
(1 row)
-- pg_stat_have_stats returns false for dropped index with stats
-SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
+SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid);
pg_stat_have_stats
--------------------
t
(1 row)
DROP index stats_test_idx1;
-SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
+SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid);
pg_stat_have_stats
--------------------
f
@@ -1415,14 +1416,14 @@ select a from stats_test_tab1 where a = 3;
3
(1 row)
-SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
+SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid);
pg_stat_have_stats
--------------------
t
(1 row)
ROLLBACK;
-SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
+SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid);
pg_stat_have_stats
--------------------
f
@@ -1437,7 +1438,7 @@ select a from stats_test_tab1 where a = 3;
3
(1 row)
-SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
+SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid);
pg_stat_have_stats
--------------------
t
@@ -1445,7 +1446,7 @@ SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
REINDEX index CONCURRENTLY stats_test_idx1;
-- false for previous oid
-SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
+SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid);
pg_stat_have_stats
--------------------
f
@@ -1453,7 +1454,7 @@ SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
-- true for new oid
SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset
-SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
+SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid);
pg_stat_have_stats
--------------------
t
@@ -1461,7 +1462,7 @@ SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
-- pg_stat_have_stats returns true for a rolled back drop index with stats
BEGIN;
-SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
+SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid);
pg_stat_have_stats
--------------------
t
@@ -1469,7 +1470,7 @@ SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
DROP index stats_test_idx1;
ROLLBACK;
-SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
+SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid);
pg_stat_have_stats
--------------------
t
diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql
index 4c265d1245c..d4623c32cd3 100644
--- a/src/test/regress/sql/stats.sql
+++ b/src/test/regress/sql/stats.sql
@@ -398,7 +398,7 @@ SELECT idx_scan, :'test_last_idx' < last_idx_scan AS idx_ok,
FROM pg_stat_all_indexes WHERE indexrelid = 'test_last_scan_pkey'::regclass;
-- check that the stats in pg_stat_all_indexes are reset
-SELECT pg_stat_reset_single_table_counters('test_last_scan_pkey'::regclass);
+SELECT pg_stat_reset_single_index_counters('test_last_scan_pkey'::regclass);
SELECT idx_scan, stats_reset IS NOT NULL AS has_stats_reset
FROM pg_stat_all_indexes WHERE indexrelid = 'test_last_scan_pkey'::regclass;
@@ -619,40 +619,40 @@ CREATE index stats_test_idx1 on stats_test_tab1(a);
SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset
SET enable_seqscan TO off;
select a from stats_test_tab1 where a = 3;
-SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
+SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid);
-- pg_stat_have_stats returns false for dropped index with stats
-SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
+SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid);
DROP index stats_test_idx1;
-SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
+SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid);
-- pg_stat_have_stats returns false for rolled back index creation
BEGIN;
CREATE index stats_test_idx1 on stats_test_tab1(a);
SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset
select a from stats_test_tab1 where a = 3;
-SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
+SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid);
ROLLBACK;
-SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
+SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid);
-- pg_stat_have_stats returns true for reindex CONCURRENTLY
CREATE index stats_test_idx1 on stats_test_tab1(a);
SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset
select a from stats_test_tab1 where a = 3;
-SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
+SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid);
REINDEX index CONCURRENTLY stats_test_idx1;
-- false for previous oid
-SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
+SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid);
-- true for new oid
SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset
-SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
+SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid);
-- pg_stat_have_stats returns true for a rolled back drop index with stats
BEGIN;
-SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
+SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid);
DROP index stats_test_idx1;
ROLLBACK;
-SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
+SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid);
-- put enable_seqscan back to on
SET enable_seqscan TO on;
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index eb3dd5481e6..8e3213954d8 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -2325,6 +2325,7 @@ PgStatShared_CustomVarEntry
PgStatShared_Database
PgStatShared_Function
PgStatShared_HashEntry
+PgStatShared_Index
PgStatShared_IO
PgStatShared_Lock
PgStatShared_Relation
@@ -2362,6 +2363,7 @@ PgStat_StatCustomFixedEntry
PgStat_StatCustomVarEntry
PgStat_StatDBEntry
PgStat_StatFuncEntry
+PgStat_StatIdxEntry
PgStat_StatReplSlotEntry
PgStat_StatSubEntry
PgStat_StatTabEntry