pg_stat_statements: Track number of times pgss entries were deallocated.
authorFujii Masao <[email protected]>
Thu, 26 Nov 2020 12:18:05 +0000 (21:18 +0900)
committerFujii Masao <[email protected]>
Thu, 26 Nov 2020 12:18:05 +0000 (21:18 +0900)
If more distinct statements than pg_stat_statements.max are observed,
pg_stat_statements entries about the least-executed statements are
deallocated. This commit enables us to track the total number of times
those entries were deallocated. That number can be viewed in the
pg_stat_statements_info view that this commit adds. It's useful when
tuning pg_stat_statements.max parameter. If it's high, i.e., the entries
are deallocated very frequently, which might cause the performance
regression and we can increase pg_stat_statements.max to avoid those
frequent deallocations.

The pg_stat_statements_info view is intended to display the statistics
of pg_stat_statements module itself. Currently it has only one column
"dealloc" indicating the number of times entries were deallocated.
But an upcoming patch will add other columns (for example, the time
at which pg_stat_statements statistics were last reset) into the view.

Author: Katsuragi Yuta, Yuki Seino
Reviewed-by: Fujii Masao
Discussion: https://postgr.es/m/0d9f1107772cf5c3f954e985464c7298@oss.nttdata.com

contrib/pg_stat_statements/Makefile
contrib/pg_stat_statements/expected/pg_stat_statements.out
contrib/pg_stat_statements/pg_stat_statements--1.8--1.9.sql [new file with mode: 0644]
contrib/pg_stat_statements/pg_stat_statements.c
contrib/pg_stat_statements/pg_stat_statements.control
contrib/pg_stat_statements/sql/pg_stat_statements.sql
doc/src/sgml/pgstatstatements.sgml
src/tools/pgindent/typedefs.list

index 081f997d703f92f51e6e0626d200c496dc026c17..3ec627b956180713760add0c76be3bc851e5ecd1 100644 (file)
@@ -6,7 +6,7 @@ OBJS = \
    pg_stat_statements.o
 
 EXTENSION = pg_stat_statements
-DATA = pg_stat_statements--1.4.sql \
+DATA = pg_stat_statements--1.4.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 \
index 2a303a7f0736eb8cd2b1a7e10c5b43c868709020..16158525cac06a43c10d492edb6859ef02f8a231 100644 (file)
@@ -861,4 +861,19 @@ SELECT query, plans, calls, rows FROM pg_stat_statements ORDER BY query COLLATE
  SELECT query, plans, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C" |     1 |     0 |    0
 (6 rows)
 
+--
+-- access to pg_stat_statements_info view
+--
+SELECT pg_stat_statements_reset();
+ pg_stat_statements_reset 
+--------------------------
+(1 row)
+
+SELECT dealloc FROM pg_stat_statements_info;
+ dealloc 
+---------
+       0
+(1 row)
+
 DROP EXTENSION pg_stat_statements;
diff --git a/contrib/pg_stat_statements/pg_stat_statements--1.8--1.9.sql b/contrib/pg_stat_statements/pg_stat_statements--1.8--1.9.sql
new file mode 100644 (file)
index 0000000..2019a4f
--- /dev/null
@@ -0,0 +1,17 @@
+/* contrib/pg_stat_statements/pg_stat_statements--1.8--1.9.sql */
+
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION pg_stat_statements UPDATE TO '1.9'" to load this file. \quit
+
+--- Define pg_stat_statements_info
+CREATE FUNCTION pg_stat_statements_info(
+    OUT dealloc bigint
+)
+RETURNS bigint
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT VOLATILE PARALLEL SAFE;
+
+CREATE VIEW pg_stat_statements_info AS
+  SELECT * FROM pg_stat_statements_info();
+
+GRANT SELECT ON pg_stat_statements_info TO PUBLIC;
index dd963c4644a1afbd9f25027c30cb55ea2f0c9e5b..70cfdb2c9d1476532dcd1a21c129437bda40510c 100644 (file)
@@ -98,7 +98,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 = 0x20171004;
+static const uint32 PGSS_FILE_HEADER = 0x20201126;
 
 /* PostgreSQL major version number, changes in which invalidate all entries */
 static const uint32 PGSS_PG_MAJOR_VERSION = PG_VERSION_NUM / 100;
@@ -193,6 +193,14 @@ typedef struct Counters
    uint64      wal_bytes;      /* total amount of WAL bytes generated */
 } Counters;
 
+/*
+ * Global statistics for pg_stat_statements
+ */
+typedef struct pgssGlobalStats
+{
+   int64       dealloc;        /* # of times entries were deallocated */
+} pgssGlobalStats;
+
 /*
  * Statistics per statement
  *
@@ -222,6 +230,7 @@ typedef struct pgssSharedState
    Size        extent;         /* current extent of query file */
    int         n_writers;      /* number of active writers to query file */
    int         gc_count;       /* query file garbage collection cycle count */
+   pgssGlobalStats stats;      /* global statistics for pgss */
 } pgssSharedState;
 
 /*
@@ -327,6 +336,7 @@ 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);
+PG_FUNCTION_INFO_V1(pg_stat_statements_info);
 
 static void pgss_shmem_startup(void);
 static void pgss_shmem_shutdown(int code, Datum arg);
@@ -554,6 +564,7 @@ pgss_shmem_startup(void)
        pgss->extent = 0;
        pgss->n_writers = 0;
        pgss->gc_count = 0;
+       pgss->stats.dealloc = 0;
    }
 
    memset(&info, 0, sizeof(info));
@@ -673,6 +684,10 @@ pgss_shmem_startup(void)
        entry->counters = temp.counters;
    }
 
+   /* Read global statistics for pg_stat_statements */
+   if (fread(&pgss->stats, sizeof(pgssGlobalStats), 1, file) != 1)
+       goto read_error;
+
    pfree(buffer);
    FreeFile(file);
    FreeFile(qfile);
@@ -794,6 +809,10 @@ pgss_shmem_shutdown(int code, Datum arg)
        }
    }
 
+   /* Dump global statistics for pg_stat_statements */
+   if (fwrite(&pgss->stats, sizeof(pgssGlobalStats), 1, file) != 1)
+       goto error;
+
    free(qbuffer);
    qbuffer = NULL;
 
@@ -1863,6 +1882,26 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo,
    tuplestore_donestoring(tupstore);
 }
 
+/*
+ * Return statistics of pg_stat_statements.
+ */
+Datum
+pg_stat_statements_info(PG_FUNCTION_ARGS)
+{
+   pgssGlobalStats stats;
+
+   /* Read global statistics for pg_stat_statements */
+   {
+       volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
+
+       SpinLockAcquire(&s->mutex);
+       stats = s->stats;
+       SpinLockRelease(&s->mutex);
+   }
+
+   PG_RETURN_INT64(stats.dealloc);
+}
+
 /*
  * Estimate shared memory space needed.
  */
@@ -2018,6 +2057,15 @@ entry_dealloc(void)
    }
 
    pfree(entries);
+
+   /* Increment the number of times entries are deallocated */
+   {
+       volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
+
+       SpinLockAcquire(&s->mutex);
+       s->stats.dealloc += 1;
+       SpinLockRelease(&s->mutex);
+   }
 }
 
 /*
@@ -2504,6 +2552,15 @@ entry_reset(Oid userid, Oid dbid, uint64 queryid)
            hash_search(pgss_hash, &entry->key, HASH_REMOVE, NULL);
            num_remove++;
        }
+
+       /* Reset global statistics for pg_stat_statements */
+       {
+           volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
+
+           SpinLockAcquire(&s->mutex);
+           s->stats.dealloc = 0;
+           SpinLockRelease(&s->mutex);
+       }
    }
 
    /* All entries are removed? */
index 65b18b11d258602d5d691651be0a46b5f56452b5..2f1ce6ed50705b64a62ba221b11c26cef4635592 100644 (file)
@@ -1,5 +1,5 @@
 # pg_stat_statements extension
 comment = 'track planning and execution statistics of all SQL statements executed'
-default_version = '1.8'
+default_version = '1.9'
 module_pathname = '$libdir/pg_stat_statements'
 relocatable = true
index e9f5bb84e38ec47df638cdb6b4d9171b0e57db61..6f58d9d0f669c5d5b0f71978c169c93da408546b 100644 (file)
@@ -358,4 +358,10 @@ SELECT 42;
 SELECT 42;
 SELECT query, plans, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
 
+--
+-- access to pg_stat_statements_info view
+--
+SELECT pg_stat_statements_reset();
+SELECT dealloc FROM pg_stat_statements_info;
+
 DROP EXTENSION pg_stat_statements;
index cf2d25b7b22fd9041ff7601eb5a60469853eea1d..81915ea69bb3da9251f966ff04279e73c75b1b09 100644 (file)
@@ -23,7 +23,9 @@
  <para>
    When <filename>pg_stat_statements</filename> is loaded, it tracks
    statistics across all databases of the server.  To access and manipulate
-   these statistics, the module provides a view, <structname>pg_stat_statements</structname>,
+   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
    <function>pg_stat_statements</function>.  These are not available globally but
    can be enabled for a specific database with
   </para>
  </sect2>
 
+ <sect2>
+  <title>The <structname>pg_stat_statements_info</structname> View</title>
+
+  <indexterm>
+   <primary>pg_stat_statements_info</primary>
+  </indexterm>
+
+  <para>
+   The statistics of the <filename>pg_stat_statements</filename> module
+   itself are tracked and made available via a view named
+   <structname>pg_stat_statements_info</structname>.  This view contains
+   only a single row.  The columns of the view are shown in
+   <xref linkend="pgstatstatementsinfo-columns"/>.
+  </para>
+
+  <table id="pgstatstatementsinfo-columns">
+   <title><structname>pg_stat_statements_info</structname> Columns</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>dealloc</structfield> <type>bigint</type>
+      </para>
+      <para>
+       Total number of times <structname>pg_stat_statements</structname>
+       entries about the least-executed statements were deallocated
+       because more distinct statements than
+       <varname>pg_stat_statements.max</varname> were observed
+      </para></entry>
+     </row>
+    </tbody>
+   </tgroup>
+  </table>
+ </sect2>
+
  <sect2>
   <title>Functions</title>
 
       specified, the default value <literal>0</literal>(invalid) is used for
       each of them and the 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 statistics.  By
-      default, this function can only be executed by superusers.  Access may be
-      granted to others using <command>GRANT</command>.
+      <literal>0</literal>(invalid), it will discard all statistics including
+      the statistics that <structname>pg_stat_statements_info</structname>
+      displays.  By default, this function can only be executed by superusers.
+      Access may be granted to others using <command>GRANT</command>.
      </para>
     </listitem>
    </varlistentry>
       statements tracked by the module (i.e., the maximum number of rows
       in the <structname>pg_stat_statements</structname> view).  If more distinct
       statements than that are observed, information about the least-executed
-      statements is discarded.
+      statements is discarded.  The number of times such information was
+      discarded can be seen in the
+      <structname>pg_stat_statements_info</structname> view.
       The default value is 5000.
       This parameter can only be set at server start.
      </para>
index 4c40ae37b26a6c37a0057371c1d3707d9bd3f4ef..b8ca8cffd9198ad5f07c35140b98adce2ef6d8c6 100644 (file)
@@ -3215,6 +3215,7 @@ pgpid_t
 pgsocket
 pgsql_thing_t
 pgssEntry
+pgssGlobalStats
 pgssHashKey
 pgssJumbleState
 pgssLocationLen