Add system view pg_stat_kind_info

This commit adds support for pg_stat_kind_info, that exposes at SQL
level data about the statistics kinds registered into a backend:
- Meta-data of a stats kind (built-in or custom, some properties).
- Number of entries, if tracking is enabled.

We have discussed the possibility of more fields (like shared memory
size for a single entry); this adds the minimum agreed on.

This is in spirit similar to pg_get_loaded_modules() for custom stats
kinds, this view providing detailed information about the stats kinds
when registered through shared_preload_libraries.

Bump catalog version.

Author: Tristan Partin <tristan@partin.io>
Reviewed-by: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Reviewed-by: Sami Imseih <samimseih@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/DI6OFGHJ1B69.25YVDEP3BABRH@partin.io
This commit is contained in:
Michael Paquier 2026-07-02 09:34:21 +09:00
parent 2e606d75c0
commit 3b066de6c0
11 changed files with 273 additions and 2 deletions

View file

@ -509,6 +509,16 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser
</entry>
</row>
<row>
<entry><structname>pg_stat_kind_info</structname><indexterm><primary>pg_stat_kind_info</primary></indexterm></entry>
<entry>
One row for each registered statistics kind, showing information
about each kind.
See <link linkend="monitoring-pg-stat-kind-info-view">
<structname>pg_stat_kind_info</structname></link> for details.
</entry>
</row>
<row>
<entry><structname>pg_stat_lock</structname><indexterm><primary>pg_stat_lock</primary></indexterm></entry>
<entry>
@ -3303,6 +3313,124 @@ description | Waiting for a newly initialized WAL file to reach durable storage
</sect2>
<sect2 id="monitoring-pg-stat-kind-info-view">
<title><structname>pg_stat_kind_info</structname></title>
<indexterm>
<primary>pg_stat_kind_info</primary>
</indexterm>
<para>
The <structname>pg_stat_kind_info</structname> view contains one row for
each registered statistics kind, including both built-in and custom kinds.
</para>
<table id="pg-stat-kind-info-view" xreflabel="pg_stat_kind_info">
<title><structname>pg_stat_kind_info</structname> View</title>
<tgroup cols="1">
<thead>
<row>
<entry role="catalog_table_entry">
<para role="column_definition">
Column Type
</para>
<para>
Description
</para>
</entry>
</row>
</thead>
<tbody>
<row>
<entry role="catalog_table_entry">
<para role="column_definition">
<structfield>id</structfield> <type>integer</type>
</para>
<para>
Numeric identifier of the statistics kind.
</para>
</entry>
</row>
<row>
<entry role="catalog_table_entry">
<para role="column_definition">
<structfield>name</structfield> <type>text</type>
</para>
<para>
Name of the statistics kind.
</para>
</entry>
</row>
<row>
<entry role="catalog_table_entry">
<para role="column_definition">
<structfield>builtin</structfield> <type>boolean</type>
</para>
<para>
True if this is a built-in statistics kind, false if it was registered
by an extension.
</para>
</entry>
</row>
<row>
<entry role="catalog_table_entry">
<para role="column_definition">
<structfield>fixed_amount</structfield> <type>boolean</type>
</para>
<para>
True if this kind tracks a fixed amount of data (a single, statically
allocated entry), false if it tracks a variable number of entries
keyed by object identifier.
</para>
</entry>
</row>
<row>
<entry role="catalog_table_entry">
<para role="column_definition">
<structfield>accessed_across_databases</structfield> <type>boolean</type>
</para>
<para>
True if entries of this kind are accessed across databases (cluster-wide
statistics), false if they are scoped to a single database.
</para>
</entry>
</row>
<row>
<entry role="catalog_table_entry">
<para role="column_definition">
<structfield>write_to_file</structfield> <type>boolean</type>
</para>
<para>
True if entries of this kind are persisted to the statistics file at
shutdown and reloaded on startup, false if they are kept only in
shared memory.
</para>
</entry>
</row>
<row>
<entry role="catalog_table_entry">
<para role="column_definition">
<structfield>entry_count</structfield> <type>bigint</type>
</para>
<para>
Number of tracked entries for this kind. For variable-numbered kinds,
this is the number of objects currently tracked.
<literal>NULL</literal> for fixed-sized statistics kinds, or if the
kind does not track entry counts.
</para>
</entry>
</row>
</tbody>
</tgroup>
</table>
</sect2>
<sect2 id="monitoring-pg-stat-lock-view">
<title><structname>pg_stat_lock</structname></title>

View file

@ -1282,6 +1282,17 @@ SELECT
b.stats_reset
FROM pg_stat_get_io() b;
CREATE VIEW pg_stat_kind_info AS
SELECT
k.id,
k.name,
k.builtin,
k.fixed_amount,
k.accessed_across_databases,
k.write_to_file,
k.entry_count
FROM pg_stat_get_kind_info() k;
CREATE VIEW pg_stat_wal AS
SELECT
w.wal_records,

View file

@ -26,6 +26,7 @@ OBJS = \
pgstat_database.o \
pgstat_function.o \
pgstat_io.o \
pgstat_kind.o \
pgstat_lock.o \
pgstat_relation.o \
pgstat_replslot.o \

View file

@ -11,6 +11,7 @@ backend_sources += files(
'pgstat_database.c',
'pgstat_function.c',
'pgstat_io.c',
'pgstat_kind.c',
'pgstat_lock.c',
'pgstat_relation.c',
'pgstat_replslot.c',

View file

@ -0,0 +1,72 @@
/*-------------------------------------------------------------------------
*
* pgstat_kind.c
* Functions related to statistics kinds.
*
* Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* src/backend/utils/activity/pgstat_kind.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "fmgr.h"
#include "funcapi.h"
#include "utils/builtins.h"
#include "utils/fmgrprotos.h"
#include "utils/pgstat_internal.h"
#include "utils/pgstat_kind.h"
#include "utils/tuplestore.h"
/*
* pg_stat_get_kind_info
*
* Get information about the statistics kinds registered into the system.
*/
Datum
pg_stat_get_kind_info(PG_FUNCTION_ARGS)
{
#define PG_STAT_KIND_INFO_COLS 7
ReturnSetInfo *rsinfo;
InitMaterializedSRF(fcinfo, 0);
rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
for (int kind = PGSTAT_KIND_MIN; kind <= PGSTAT_KIND_MAX; kind++)
{
Datum values[PG_STAT_KIND_INFO_COLS] = {0};
bool nulls[PG_STAT_KIND_INFO_COLS] = {0};
const PgStat_KindInfo *info;
info = pgstat_get_kind_info(kind);
if (info == NULL)
continue;
values[0] = Int32GetDatum(kind);
values[1] = CStringGetTextDatum(info->name);
values[2] = BoolGetDatum(pgstat_is_kind_builtin(kind));
values[3] = BoolGetDatum(info->fixed_amount);
values[4] = BoolGetDatum(info->accessed_across_databases);
values[5] = BoolGetDatum(info->write_to_file);
/*
* When track_entry_count is disabled, use NULL. Fixed-sized stats
* kinds report NULL here.
*/
if (info->track_entry_count)
values[6] = Int64GetDatum(pgstat_get_entry_count(kind));
else
nulls[6] = true;
tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
}
return (Datum) 0;
#undef PG_STAT_KIND_INFO_COLS
}

View file

@ -57,6 +57,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 202607011
#define CATALOG_VERSION_NO 202607021
#endif

View file

@ -6078,6 +6078,14 @@
proargnames => '{backend_pid,backend_type,object,context,reads,read_bytes,read_time,writes,write_bytes,write_time,writebacks,writeback_time,extends,extend_bytes,extend_time,hits,evictions,reuses,fsyncs,fsync_time,stats_reset}',
prosrc => 'pg_stat_get_backend_io' },
{ oid => '8683', descr => 'statistics: information about statistics kinds',
proname => 'pg_stat_get_kind_info', prorows => '20', proretset => 't',
provolatile => 'v', proparallel => 'r', prorettype => 'record',
proargtypes => '', proallargtypes => '{int4,text,bool,bool,bool,bool,int8}',
proargmodes => '{o,o,o,o,o,o,o}',
proargnames => '{id,name,builtin,fixed_amount,accessed_across_databases,write_to_file,entry_count}',
prosrc => 'pg_stat_get_kind_info' },
{ oid => '1136', descr => 'statistics: information about WAL activity',
proname => 'pg_stat_get_wal', proisstrict => 'f', provolatile => 's',
proparallel => 'r', prorettype => 'record', proargtypes => '',

View file

@ -27,6 +27,18 @@ $node->start;
$node->safe_psql('postgres', q(CREATE EXTENSION test_custom_var_stats));
$node->safe_psql('postgres', q(CREATE EXTENSION test_custom_fixed_stats));
# Verify custom stats kinds appear in pg_stat_kind_info.
my $result = $node->safe_psql(
'postgres',
q(SELECT id, name, builtin, fixed_amount, accessed_across_databases,
write_to_file
FROM pg_stat_kind_info
WHERE name LIKE 'test_custom%' ORDER BY id));
is( $result,
qq{25|test_custom_var_stats|f|f|t|t
26|test_custom_fixed_stats|f|t|f|t},
"custom stats kinds visible in pg_stat_kind_info");
# Create entries for variable-sized stats.
$node->safe_psql('postgres',
q(select test_custom_stats_var_create('entry1', 'Test entry 1')));
@ -63,7 +75,7 @@ $node->safe_psql('postgres', q(select test_custom_stats_fixed_update()));
$node->safe_psql('postgres', q(select test_custom_stats_fixed_update()));
# Test data reports.
my $result = $node->safe_psql('postgres',
$result = $node->safe_psql('postgres',
q(select * from test_custom_stats_var_report('entry1')));
is( $result,
"entry1|2|Test entry 1",

View file

@ -1967,6 +1967,14 @@ pg_stat_io| SELECT backend_type,
fsync_time,
stats_reset
FROM pg_stat_get_io() b(backend_type, object, context, reads, read_bytes, read_time, writes, write_bytes, write_time, writebacks, writeback_time, extends, extend_bytes, extend_time, hits, evictions, reuses, fsyncs, fsync_time, stats_reset);
pg_stat_kind_info| SELECT id,
name,
builtin,
fixed_amount,
accessed_across_databases,
write_to_file,
entry_count
FROM pg_stat_get_kind_info() k(id, name, builtin, fixed_amount, accessed_across_databases, write_to_file, entry_count);
pg_stat_lock| SELECT locktype,
waits,
wait_time,

View file

@ -113,6 +113,29 @@ walwriter|wal|init
walwriter|wal|normal
(95 rows)
\a
-- List of registered statistics kinds.
SELECT id, name, fixed_amount,
accessed_across_databases AS across_db, write_to_file
FROM pg_stat_kind_info
WHERE builtin
ORDER BY id;
id | name | fixed_amount | across_db | write_to_file
----+--------------+--------------+-----------+---------------
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)
-- ensure that both seqscan and indexscan plans are allowed
SET enable_seqscan TO on;
SET enable_indexscan TO on;

View file

@ -14,6 +14,13 @@ SELECT backend_type, object, context FROM pg_stat_io
ORDER BY backend_type COLLATE "C", object COLLATE "C", context COLLATE "C";
\a
-- List of registered statistics kinds.
SELECT id, name, fixed_amount,
accessed_across_databases AS across_db, write_to_file
FROM pg_stat_kind_info
WHERE builtin
ORDER BY id;
-- ensure that both seqscan and indexscan plans are allowed
SET enable_seqscan TO on;
SET enable_indexscan TO on;