Hi, Anton! Thank you for your review!
On Mon, 2021-10-18 at 22:11 +0300, Anton A. Melnikov wrote: > So i suppose that additional vars loc_min and loc_max is a right way > to do it. I've added the following fields to the pg_stat_statements view: min_plan_time_local float8, max_plan_time_local float8, min_exec_time_local float8, max_exec_time_local float8 and a function that is able to reset those fields: CREATE FUNCTION pg_stat_statements_reset_local(IN userid Oid DEFAULT 0, IN dbid Oid DEFAULT 0, IN queryid bigint DEFAULT 0 ) It resets the local fields mentioned above and updates the new field local_stats_since timestamp with time zone with the current timestamp. All other statement statistics are remains unchanged. After the reset _local fields will have NULL values till the next statement execution. > And one more thing, if there was a reset of stats between two > samples, > then i think it is the best to ignore the new values, > since they were obtained for an incomplete period. > This patch, thanks to the saved time stamp, makes possible > to determine the presence of reset between samples and > there should not be a problem to realize such algorithm. Yes, it seems this is up to the sampling solution. Maybe in some cases incomplete information will be better than nothing... Anyway we have all necessary data now. > The only thing I could suggest to your notice > is a small cosmetic edit to replace > the numeric value in #define on line 1429 of pg_stat_statements.c > by one of the constants defined above. Hmm. I've left it just like it was before me. But it seems, you are right. I've attached a new version of a patch. The first_seen column was renamed to stats_since - it seems to be more self-explaining to me. But I'm not sure in the current naming at all. The tests is not ready yet, but any thoughts about the patch are welcome right now. -- Andrei Zubkov Postgres Professional: http://www.postgrespro.com The Russian Postgres Company
From bea0ae9fd062ee1810c9ff2d5f1be98a19114d84 Mon Sep 17 00:00:00 2001 From: Andrei Zubkov <zub...@moonset.ru> Date: Fri, 3 Dec 2021 16:25:17 +0300 Subject: [PATCH] pg_stat_statements: Track statement entry timestamp This patch adds stats_since column to the pg_stat_statements view. This column is populated with the current timestamp when a new statement is added to the pg_stat_statements hashtable. This column provides clean information about statistics collection time interval for each statement. Besides it can be used by sampling solutions to detect situations when a statement was evicted and returned back between two samples. Such sampling solution could derive any pg_stat_statements statistic value for an interval between two samples with except of all min/max statistics. To address this issue this patch adds the following columns: min_plan_time_local float8, max_plan_time_local float8, min_exec_time_local float8, max_exec_time_local float8 And a function to reset those statistics during a sample: CREATE FUNCTION pg_stat_statements_reset_local(IN userid Oid DEFAULT 0, IN dbid Oid DEFAULT 0, IN queryid bigint DEFAULT 0 ) The timestamp of last local statistics reset is stored for every statement in a column: local_stats_since timestamp with time zone Discussion: https://www.postgresql.org/message-id/flat/72e80e7b160a6eb189df9ef6f068cce3765d37f8.camel%40moonset.ru --- contrib/pg_stat_statements/Makefile | 3 +- .../expected/pg_stat_statements.out | 29 +++ .../pg_stat_statements--1.9--1.10.sql | 72 +++++++ .../pg_stat_statements/pg_stat_statements.c | 200 +++++++++++++++++- .../pg_stat_statements.control | 2 +- .../sql/pg_stat_statements.sql | 9 + doc/src/sgml/pgstatstatements.sgml | 111 +++++++++- 7 files changed, 419 insertions(+), 7 deletions(-) create mode 100644 contrib/pg_stat_statements/pg_stat_statements--1.9--1.10.sql diff --git a/contrib/pg_stat_statements/Makefile b/contrib/pg_stat_statements/Makefile index 7fabd96f38..edc40c8bbf 100644 --- a/contrib/pg_stat_statements/Makefile +++ b/contrib/pg_stat_statements/Makefile @@ -6,7 +6,8 @@ OBJS = \ pg_stat_statements.o EXTENSION = pg_stat_statements -DATA = pg_stat_statements--1.4.sql pg_stat_statements--1.8--1.9.sql \ +DATA = pg_stat_statements--1.4.sql \ + pg_stat_statements--1.9--1.10.sql pg_stat_statements--1.8--1.9.sql \ pg_stat_statements--1.7--1.8.sql pg_stat_statements--1.6--1.7.sql \ pg_stat_statements--1.5--1.6.sql pg_stat_statements--1.4--1.5.sql \ pg_stat_statements--1.3--1.4.sql pg_stat_statements--1.2--1.3.sql \ diff --git a/contrib/pg_stat_statements/expected/pg_stat_statements.out b/contrib/pg_stat_statements/expected/pg_stat_statements.out index e0abe34bb6..9388490073 100644 --- a/contrib/pg_stat_statements/expected/pg_stat_statements.out +++ b/contrib/pg_stat_statements/expected/pg_stat_statements.out @@ -1077,4 +1077,33 @@ SELECT COUNT(*) FROM pg_stat_statements WHERE query LIKE '%SELECT GROUPING%'; 2 (1 row) +-- +-- statement timestamps +-- +SELECT pg_stat_statements_reset(); + pg_stat_statements_reset +-------------------------- + +(1 row) + +SELECT 1 AS "STMTTS1"; + STMTTS1 +--------- + 1 +(1 row) + +SELECT now() AS ref_ts \gset +SELECT 1,2 AS "STMTTS2"; + ?column? | STMTTS2 +----------+--------- + 1 | 2 +(1 row) + +SELECT first_seen >= :'ref_ts', count(*) FROM pg_stat_statements WHERE query LIKE '%STMTTS%' GROUP BY first_seen >= :'ref_ts' ORDER BY first_seen >= :'ref_ts'; + ?column? | count +----------+------- + f | 1 + t | 1 +(2 rows) + DROP EXTENSION pg_stat_statements; diff --git a/contrib/pg_stat_statements/pg_stat_statements--1.9--1.10.sql b/contrib/pg_stat_statements/pg_stat_statements--1.9--1.10.sql new file mode 100644 index 0000000000..00f5f1c933 --- /dev/null +++ b/contrib/pg_stat_statements/pg_stat_statements--1.9--1.10.sql @@ -0,0 +1,72 @@ +/* contrib/pg_stat_statements/pg_stat_statements--1.9--1.10.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION pg_stat_statements UPDATE TO '1.10'" to load this file. \quit + +/* We need to redefine a view and a function */ +/* First we have to remove them from the extension */ +ALTER EXTENSION pg_stat_statements DROP VIEW pg_stat_statements; +ALTER EXTENSION pg_stat_statements DROP FUNCTION pg_stat_statements(boolean); + +/* Then we can drop them */ +DROP VIEW pg_stat_statements; +DROP FUNCTION pg_stat_statements(boolean); + +/* Now redefine */ +CREATE FUNCTION pg_stat_statements(IN showtext boolean, + OUT userid oid, + OUT dbid oid, + OUT toplevel bool, + OUT queryid bigint, + OUT query text, + OUT plans int8, + OUT total_plan_time float8, + OUT min_plan_time float8, + OUT max_plan_time float8, + OUT mean_plan_time float8, + OUT stddev_plan_time float8, + OUT min_plan_time_local float8, + OUT max_plan_time_local float8, + OUT calls int8, + OUT total_exec_time float8, + OUT min_exec_time float8, + OUT max_exec_time float8, + OUT mean_exec_time float8, + OUT stddev_exec_time float8, + OUT min_exec_time_local float8, + OUT max_exec_time_local float8, + OUT rows int8, + OUT shared_blks_hit int8, + OUT shared_blks_read int8, + OUT shared_blks_dirtied int8, + OUT shared_blks_written int8, + OUT local_blks_hit int8, + OUT local_blks_read int8, + OUT local_blks_dirtied int8, + OUT local_blks_written int8, + OUT temp_blks_read int8, + OUT temp_blks_written int8, + OUT blk_read_time float8, + OUT blk_write_time float8, + OUT wal_records int8, + OUT wal_fpi int8, + OUT wal_bytes numeric, + OUT stats_since timestamp with time zone, + OUT local_stats_since timestamp with time zone +) +RETURNS SETOF record +AS 'MODULE_PATHNAME', 'pg_stat_statements_1_10' +LANGUAGE C STRICT VOLATILE PARALLEL SAFE; + +CREATE VIEW pg_stat_statements AS + SELECT * FROM pg_stat_statements(true); + +CREATE FUNCTION pg_stat_statements_reset_local(IN userid Oid DEFAULT 0, + IN dbid Oid DEFAULT 0, + IN queryid bigint DEFAULT 0 +) +RETURNS void +AS 'MODULE_PATHNAME', 'pg_stat_statements_reset_local_1_10' +LANGUAGE C STRICT PARALLEL SAFE; + +GRANT SELECT ON pg_stat_statements TO PUBLIC; diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c index 726ba59e2b..43467da0eb 100644 --- a/contrib/pg_stat_statements/pg_stat_statements.c +++ b/contrib/pg_stat_statements/pg_stat_statements.c @@ -88,7 +88,7 @@ PG_MODULE_MAGIC; #define PGSS_TEXT_FILE PG_STAT_TMP_DIR "/pgss_query_texts.stat" /* Magic number identifying the stats file format */ -static const uint32 PGSS_FILE_HEADER = 0x20201227; +static const uint32 PGSS_FILE_HEADER = 0x20210322; /* PostgreSQL major version number, changes in which invalidate all entries */ static const uint32 PGSS_PG_MAJOR_VERSION = PG_VERSION_NUM / 100; @@ -121,7 +121,8 @@ typedef enum pgssVersion PGSS_V1_2, PGSS_V1_3, PGSS_V1_8, - PGSS_V1_9 + PGSS_V1_9, + PGSS_V1_10 } pgssVersion; typedef enum pgssStoreKind @@ -168,6 +169,10 @@ typedef struct Counters * msec */ double max_time[PGSS_NUMKIND]; /* maximum planning/execution time in * msec */ + double min_time_local[PGSS_NUMKIND]; /* minimum planning/execution time + * since local reset in msec */ + double max_time_local[PGSS_NUMKIND]; /* maximum planning/execution time + * since local reset in msec */ double mean_time[PGSS_NUMKIND]; /* mean planning/execution time in * msec */ double sum_var_time[PGSS_NUMKIND]; /* sum of variances in @@ -214,6 +219,8 @@ typedef struct pgssEntry Size query_offset; /* query text offset in external file */ int query_len; /* # of valid bytes in query string, or -1 */ int encoding; /* query text encoding */ + TimestampTz gstats_since; /* timestamp of entry allocation moment */ + TimestampTz lstats_since; /* timestamp of last local statistics reset */ slock_t mutex; /* protects the counters only */ } pgssEntry; @@ -298,10 +305,12 @@ void _PG_fini(void); PG_FUNCTION_INFO_V1(pg_stat_statements_reset); PG_FUNCTION_INFO_V1(pg_stat_statements_reset_1_7); +PG_FUNCTION_INFO_V1(pg_stat_statements_reset_local_1_10); PG_FUNCTION_INFO_V1(pg_stat_statements_1_2); PG_FUNCTION_INFO_V1(pg_stat_statements_1_3); PG_FUNCTION_INFO_V1(pg_stat_statements_1_8); PG_FUNCTION_INFO_V1(pg_stat_statements_1_9); +PG_FUNCTION_INFO_V1(pg_stat_statements_1_10); PG_FUNCTION_INFO_V1(pg_stat_statements); PG_FUNCTION_INFO_V1(pg_stat_statements_info); @@ -345,6 +354,7 @@ static char *qtext_fetch(Size query_offset, int query_len, char *buffer, Size buffer_size); static bool need_gc_qtexts(void); static void gc_qtexts(void); +static void entry_reset_local(Oid userid, Oid dbid, uint64 queryid); static void entry_reset(Oid userid, Oid dbid, uint64 queryid); static char *generate_normalized_query(JumbleState *jstate, const char *query, int query_loc, int *query_len_p); @@ -649,6 +659,8 @@ pgss_shmem_startup(void) /* copy in the actual stats */ entry->counters = temp.counters; + entry->gstats_since = temp.gstats_since; + entry->lstats_since = temp.lstats_since; } /* Read global statistics for pg_stat_statements */ @@ -1340,6 +1352,8 @@ pgss_store(const char *query, uint64 queryId, e->counters.min_time[kind] = total_time; e->counters.max_time[kind] = total_time; e->counters.mean_time[kind] = total_time; + e->counters.min_time_local[kind] = total_time; + e->counters.max_time_local[kind] = total_time; } else { @@ -1359,6 +1373,23 @@ pgss_store(const char *query, uint64 queryId, e->counters.min_time[kind] = total_time; if (e->counters.max_time[kind] < total_time) e->counters.max_time[kind] = total_time; + + /* + * Calculate local min and max time. min_local > max_local + * means that local reset was happen + */ + if (e->counters.min_time_local[kind] > e->counters.max_time_local[kind]) + { + e->counters.min_time_local[kind] = total_time; + e->counters.max_time_local[kind] = total_time; + } + else + { + if (e->counters.min_time_local[kind] > total_time) + e->counters.min_time_local[kind] = total_time; + if (e->counters.max_time_local[kind] < total_time) + e->counters.max_time_local[kind] = total_time; + } } e->counters.rows += rows; e->counters.shared_blks_hit += bufusage->shared_blks_hit; @@ -1389,6 +1420,25 @@ done: pfree(norm_query); } +/* + * Reset local statement statistics corresponding to userid, dbid, and queryid. + */ +Datum +pg_stat_statements_reset_local_1_10(PG_FUNCTION_ARGS) +{ + Oid userid; + Oid dbid; + uint64 queryid; + + userid = PG_GETARG_OID(0); + dbid = PG_GETARG_OID(1); + queryid = (uint64) PG_GETARG_INT64(2); + + entry_reset_local(userid, dbid, queryid); + + PG_RETURN_VOID(); +} + /* * Reset statement statistics corresponding to userid, dbid, and queryid. */ @@ -1426,7 +1476,8 @@ pg_stat_statements_reset(PG_FUNCTION_ARGS) #define PG_STAT_STATEMENTS_COLS_V1_3 23 #define PG_STAT_STATEMENTS_COLS_V1_8 32 #define PG_STAT_STATEMENTS_COLS_V1_9 33 -#define PG_STAT_STATEMENTS_COLS 33 /* maximum of above */ +#define PG_STAT_STATEMENTS_COLS_V1_10 39 +#define PG_STAT_STATEMENTS_COLS 39 /* maximum of above */ /* * Retrieve statement statistics. @@ -1438,6 +1489,16 @@ pg_stat_statements_reset(PG_FUNCTION_ARGS) * expected API version is identified by embedding it in the C name of the * function. Unfortunately we weren't bright enough to do that for 1.1. */ +Datum +pg_stat_statements_1_10(PG_FUNCTION_ARGS) +{ + bool showtext = PG_GETARG_BOOL(0); + + pg_stat_statements_internal(fcinfo, PGSS_V1_10, showtext); + + return (Datum) 0; +} + Datum pg_stat_statements_1_9(PG_FUNCTION_ARGS) { @@ -1571,6 +1632,10 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo, if (api_version != PGSS_V1_9) elog(ERROR, "incorrect number of output arguments"); break; + case PG_STAT_STATEMENTS_COLS_V1_10: + if (api_version != PGSS_V1_10) + elog(ERROR, "incorrect number of output arguments"); + break; default: elog(ERROR, "incorrect number of output arguments"); } @@ -1656,6 +1721,8 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo, Counters tmp; double stddev; int64 queryid = entry->key.queryid; + TimestampTz gstats_since; + TimestampTz lstats_since; memset(values, 0, sizeof(values)); memset(nulls, 0, sizeof(nulls)); @@ -1724,6 +1791,8 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo, SpinLockAcquire(&e->mutex); tmp = e->counters; + gstats_since = e->gstats_since; + lstats_since = e->lstats_since; SpinLockRelease(&e->mutex); } @@ -1758,6 +1827,21 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo, else stddev = 0.0; values[i++] = Float8GetDatumFast(stddev); + + if (tmp.max_time_local[kind] < tmp.min_time_local[kind]) + { + /* + * There was not executions since last local min/max reset + * so, we should return nulls. + */ + nulls[i++] = true; + nulls[i++] = true; + } + else + { + values[i++] = Float8GetDatumFast(tmp.min_time_local[kind]); + values[i++] = Float8GetDatumFast(tmp.max_time_local[kind]); + } } } values[i++] = Int64GetDatumFast(tmp.rows); @@ -1795,6 +1879,11 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo, Int32GetDatum(-1)); values[i++] = wal_bytes; } + if (api_version >= PGSS_V1_10) + { + values[i++] = TimestampTzGetDatum(gstats_since); + values[i++] = TimestampTzGetDatum(lstats_since); + } Assert(i == (api_version == PGSS_V1_0 ? PG_STAT_STATEMENTS_COLS_V1_0 : api_version == PGSS_V1_1 ? PG_STAT_STATEMENTS_COLS_V1_1 : @@ -1802,6 +1891,7 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo, api_version == PGSS_V1_3 ? PG_STAT_STATEMENTS_COLS_V1_3 : api_version == PGSS_V1_8 ? PG_STAT_STATEMENTS_COLS_V1_8 : api_version == PGSS_V1_9 ? PG_STAT_STATEMENTS_COLS_V1_9 : + api_version == PGSS_V1_10 ? PG_STAT_STATEMENTS_COLS_V1_10 : -1 /* fail if you forget to update this assert */ )); tuplestore_putvalues(tupstore, tupdesc, values, nulls); @@ -1917,6 +2007,8 @@ entry_alloc(pgssHashKey *key, Size query_offset, int query_len, int encoding, entry->query_offset = query_offset; entry->query_len = query_len; entry->encoding = encoding; + entry->gstats_since = GetCurrentTimestamp(); + entry->lstats_since = entry->gstats_since; } return entry; @@ -2463,6 +2555,106 @@ gc_fail: record_gc_qtexts(); } +/* + * Reset local statistic values of specified entries + */ +static void +entry_reset_local(Oid userid, Oid dbid, uint64 queryid) +{ + HASH_SEQ_STATUS hash_seq; + pgssEntry *entry; + Counters *entry_counters; + pgssHashKey key; + TimestampTz stats_reset_local; + + if (!pgss || !pgss_hash) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("pg_stat_statements must be loaded via shared_preload_libraries"))); + + LWLockAcquire(pgss->lock, LW_EXCLUSIVE); + + stats_reset_local = GetCurrentTimestamp(); + + if (userid != 0 && dbid != 0 && queryid != UINT64CONST(0)) + { + /* If all the parameters are available, use the fast path. */ + memset(&key, 0, sizeof(pgssHashKey)); + key.userid = userid; + key.dbid = dbid; + key.queryid = queryid; + + /* + * Reset locals, starting with the nested-level entry + * For min/max values reset sign is min > max + */ + key.toplevel = false; + entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_FIND, NULL); + if (entry) /* found */ + { + entry_counters = &entry->counters; + for (int kind = 0; kind < PGSS_NUMKIND; kind++) + { + entry_counters->max_time_local[kind] = 0; + entry_counters->min_time_local[kind] = 1; + } + entry->lstats_since = stats_reset_local; + } + + /* Reset locals for top level statements */ + key.toplevel = true; + + entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_FIND, NULL); + if (entry) /* found */ + { + entry_counters = &entry->counters; + for (int kind = 0; kind < PGSS_NUMKIND; kind++) + { + entry_counters->max_time_local[kind] = 0; + entry_counters->min_time_local[kind] = 1; + } + entry->lstats_since = stats_reset_local; + } + } + else if (userid != 0 || dbid != 0 || queryid != UINT64CONST(0)) + { + /* Reset locals for entries corresponding to valid parameters. */ + hash_seq_init(&hash_seq, pgss_hash); + while ((entry = hash_seq_search(&hash_seq)) != NULL) + { + if ((!userid || entry->key.userid == userid) && + (!dbid || entry->key.dbid == dbid) && + (!queryid || entry->key.queryid == queryid)) + { + entry_counters = &entry->counters; + for (int kind = 0; kind < PGSS_NUMKIND; kind++) + { + entry_counters->max_time_local[kind] = 0; + entry_counters->min_time_local[kind] = 1; + } + entry->lstats_since = stats_reset_local; + } + } + } + else + { + /* Reset locals for all entries. */ + hash_seq_init(&hash_seq, pgss_hash); + while ((entry = hash_seq_search(&hash_seq)) != NULL) + { + entry_counters = &entry->counters; + for (int kind = 0; kind < PGSS_NUMKIND; kind++) + { + entry_counters->max_time_local[kind] = 0; + entry_counters->min_time_local[kind] = 1; + } + entry->lstats_since = stats_reset_local; + } + } + + LWLockRelease(pgss->lock); +} + /* * Release entries corresponding to parameters passed. */ @@ -2492,7 +2684,7 @@ entry_reset(Oid userid, Oid dbid, uint64 queryid) key.dbid = dbid; key.queryid = queryid; - /* Remove the key if it exists, starting with the top-level entry */ + /* Remove the key if it exists, starting with the nested-level entry */ key.toplevel = false; entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_REMOVE, NULL); if (entry) /* found */ diff --git a/contrib/pg_stat_statements/pg_stat_statements.control b/contrib/pg_stat_statements/pg_stat_statements.control index 2f1ce6ed50..0747e48138 100644 --- a/contrib/pg_stat_statements/pg_stat_statements.control +++ b/contrib/pg_stat_statements/pg_stat_statements.control @@ -1,5 +1,5 @@ # pg_stat_statements extension comment = 'track planning and execution statistics of all SQL statements executed' -default_version = '1.9' +default_version = '1.10' module_pathname = '$libdir/pg_stat_statements' relocatable = true diff --git a/contrib/pg_stat_statements/sql/pg_stat_statements.sql b/contrib/pg_stat_statements/sql/pg_stat_statements.sql index dffd2c8c18..44a766c9a8 100644 --- a/contrib/pg_stat_statements/sql/pg_stat_statements.sql +++ b/contrib/pg_stat_statements/sql/pg_stat_statements.sql @@ -442,4 +442,13 @@ SELECT ( SELECT COUNT(*) FROM pg_stat_statements WHERE query LIKE '%SELECT GROUPING%'; +-- +-- statement timestamps +-- +SELECT pg_stat_statements_reset(); +SELECT 1 AS "STMTTS1"; +SELECT now() AS ref_ts \gset +SELECT 1,2 AS "STMTTS2"; +SELECT first_seen >= :'ref_ts', count(*) FROM pg_stat_statements WHERE query LIKE '%STMTTS%' GROUP BY first_seen >= :'ref_ts' ORDER BY first_seen >= :'ref_ts'; + DROP EXTENSION pg_stat_statements; diff --git a/doc/src/sgml/pgstatstatements.sgml b/doc/src/sgml/pgstatstatements.sgml index bc9d5bdbe3..b10c24d212 100644 --- a/doc/src/sgml/pgstatstatements.sgml +++ b/doc/src/sgml/pgstatstatements.sgml @@ -30,7 +30,8 @@ these statistics, the module provides views <structname>pg_stat_statements</structname> and <structname>pg_stat_statements_info</structname>, - and the utility functions <function>pg_stat_statements_reset</function> and + and the utility functions <function>pg_stat_statements_reset</function>, + <function>pg_stat_statements_reset_local</function> and <function>pg_stat_statements</function>. These are not available globally but can be enabled for a specific database with <command>CREATE EXTENSION pg_stat_statements</command>. @@ -180,6 +181,38 @@ </para></entry> </row> + <row> + <entry role="catalog_table_entry"><para role="column_definition"> + <structfield>min_plan_time_local</structfield> <type>double precision</type> + </para> + <para> + Minimum time spent planning the statement since + <structfield>local_stats_since</structfield>, in milliseconds + (if <varname>pg_stat_statements.track_planning</varname> is enabled, + otherwise zero) + </para> + <para> + Function <function>pg_stat_statements_reset_local</function> resets this + value + </para></entry> + </row> + + <row> + <entry role="catalog_table_entry"><para role="column_definition"> + <structfield>max_plan_time_local</structfield> <type>double precision</type> + </para> + <para> + Maximum time spent planning the statement since + <structfield>local_stats_since</structfield>, in milliseconds + (if <varname>pg_stat_statements.track_planning</varname> is enabled, + otherwise zero) + </para> + <para> + Function <function>pg_stat_statements_reset_local</function> resets this + value + </para></entry> + </row> + <row> <entry role="catalog_table_entry"><para role="column_definition"> <structfield>calls</structfield> <type>bigint</type> @@ -234,6 +267,34 @@ </para></entry> </row> + <row> + <entry role="catalog_table_entry"><para role="column_definition"> + <structfield>min_exec_time_local</structfield> <type>double precision</type> + </para> + <para> + Minimum time spent executing the statement since + <structfield>local_stats_since</structfield>, in milliseconds + </para> + <para> + Function <function>pg_stat_statements_reset_local</function> resets this + value + </para></entry> + </row> + + <row> + <entry role="catalog_table_entry"><para role="column_definition"> + <structfield>max_exec_time_local</structfield> <type>double precision</type> + </para> + <para> + Maximum time spent executing the statement since + <structfield>local_stats_since</structfield>, in milliseconds + </para> + <para> + Function <function>pg_stat_statements_reset_local</function> resets this + value + </para></entry> + </row> + <row> <entry role="catalog_table_entry"><para role="column_definition"> <structfield>rows</structfield> <type>bigint</type> @@ -379,6 +440,23 @@ Total amount of WAL generated by the statement in bytes </para></entry> </row> + + <row> + <entry role="catalog_table_entry"><para role="column_definition"> + <structfield>stats_since</structfield> <type>timestamp with time zone</type> + </para> + <para> + Timestamp of statistics gathering start for the statement + </para></entry> + </row> + <row> + <entry role="catalog_table_entry"><para role="column_definition"> + <structfield>local_stats_since</structfield> <type>timestamp with time zone</type> + </para> + <para> + Timestamp of local statistics gathering start for the statement. + </para></entry> + </row> </tbody> </tgroup> </table> @@ -595,6 +673,37 @@ </listitem> </varlistentry> + <varlistentry> + <term> + <function>pg_stat_statements_reset_local(userid Oid, dbid Oid, queryid bigint) returns void</function> + <indexterm> + <primary>pg_stat_statements_reset_local</primary> + </indexterm> + </term> + + <listitem> + <para> + <function>pg_stat_statements_reset_local</function> discards only the local + statistics (<structfield>min_plan_time_local</structfield>, + <structfield>max_plan_time_local</structfield>, + <structfield>min_exec_time_local</structfield> and + <structfield>max_exec_time_local</structfield>) + gathered so far by <filename>pg_stat_statements</filename> corresponding + to the specified <structfield>userid</structfield>, <structfield>dbid</structfield> + and <structfield>queryid</structfield>. If any of the parameters are not + specified, the default value <literal>0</literal>(invalid) is used for + each of them and the local statistics that match with other parameters will be + reset. If no parameter is specified or all the specified parameters are + <literal>0</literal>(invalid), it will discard all local statistics. + Discarding the local statistics of a statement this function will update + the value of <structfield>local_stats_since</structfield> with the current + timestamp. + By default, this function can only be executed by superusers. + Access may be granted to others using <command>GRANT</command>. + </para> + </listitem> + </varlistentry> + <varlistentry> <term> <function>pg_stat_statements(showtext boolean) returns setof record</function> -- 2.30.2