Add stats for min, max, mean, stddev times to pg_stat_statements.
The new fields are min_time, max_time, mean_time and stddev_time. Based on an original patch from Mitsumasa KONDO, modified by me. Reviewed by Petr Jelínek.
This commit is contained in:
parent
8816af65e4
commit
717f709532
@ -4,8 +4,9 @@ MODULE_big = pg_stat_statements
|
|||||||
OBJS = pg_stat_statements.o $(WIN32RES)
|
OBJS = pg_stat_statements.o $(WIN32RES)
|
||||||
|
|
||||||
EXTENSION = pg_stat_statements
|
EXTENSION = pg_stat_statements
|
||||||
DATA = pg_stat_statements--1.2.sql pg_stat_statements--1.1--1.2.sql \
|
DATA = pg_stat_statements--1.3.sql pg_stat_statements--1.2--1.3.sql \
|
||||||
pg_stat_statements--1.0--1.1.sql pg_stat_statements--unpackaged--1.0.sql
|
pg_stat_statements--1.1--1.2.sql pg_stat_statements--1.0--1.1.sql \
|
||||||
|
pg_stat_statements--unpackaged--1.0.sql
|
||||||
PGFILEDESC = "pg_stat_statements - execution statistics of SQL statements"
|
PGFILEDESC = "pg_stat_statements - execution statistics of SQL statements"
|
||||||
|
|
||||||
ifdef USE_PGXS
|
ifdef USE_PGXS
|
||||||
|
47
contrib/pg_stat_statements/pg_stat_statements--1.2--1.3.sql
Normal file
47
contrib/pg_stat_statements/pg_stat_statements--1.2--1.3.sql
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/* contrib/pg_stat_statements/pg_stat_statements--1.2--1.3.sql */
|
||||||
|
|
||||||
|
-- complain if script is sourced in psql, rather than via ALTER EXTENSION
|
||||||
|
\echo Use "ALTER EXTENSION pg_stat_statements UPDATE TO '1.3'" to load this file. \quit
|
||||||
|
|
||||||
|
/* 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 queryid bigint,
|
||||||
|
OUT query text,
|
||||||
|
OUT calls int8,
|
||||||
|
OUT total_time float8,
|
||||||
|
OUT min_time float8,
|
||||||
|
OUT max_time float8,
|
||||||
|
OUT mean_time float8,
|
||||||
|
OUT stddev_time 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
|
||||||
|
)
|
||||||
|
RETURNS SETOF record
|
||||||
|
AS 'MODULE_PATHNAME', 'pg_stat_statements_1_3'
|
||||||
|
LANGUAGE C STRICT VOLATILE;
|
||||||
|
|
||||||
|
CREATE VIEW pg_stat_statements AS
|
||||||
|
SELECT * FROM pg_stat_statements(true);
|
||||||
|
|
||||||
|
GRANT SELECT ON pg_stat_statements TO PUBLIC;
|
@ -1,4 +1,4 @@
|
|||||||
/* contrib/pg_stat_statements/pg_stat_statements--1.2.sql */
|
/* contrib/pg_stat_statements/pg_stat_statements--1.3.sql */
|
||||||
|
|
||||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||||
\echo Use "CREATE EXTENSION pg_stat_statements" to load this file. \quit
|
\echo Use "CREATE EXTENSION pg_stat_statements" to load this file. \quit
|
||||||
@ -16,6 +16,10 @@ CREATE FUNCTION pg_stat_statements(IN showtext boolean,
|
|||||||
OUT query text,
|
OUT query text,
|
||||||
OUT calls int8,
|
OUT calls int8,
|
||||||
OUT total_time float8,
|
OUT total_time float8,
|
||||||
|
OUT min_time float8,
|
||||||
|
OUT max_time float8,
|
||||||
|
OUT mean_time float8,
|
||||||
|
OUT stddev_time float8,
|
||||||
OUT rows int8,
|
OUT rows int8,
|
||||||
OUT shared_blks_hit int8,
|
OUT shared_blks_hit int8,
|
||||||
OUT shared_blks_read int8,
|
OUT shared_blks_read int8,
|
||||||
@ -31,7 +35,7 @@ CREATE FUNCTION pg_stat_statements(IN showtext boolean,
|
|||||||
OUT blk_write_time float8
|
OUT blk_write_time float8
|
||||||
)
|
)
|
||||||
RETURNS SETOF record
|
RETURNS SETOF record
|
||||||
AS 'MODULE_PATHNAME', 'pg_stat_statements_1_2'
|
AS 'MODULE_PATHNAME', 'pg_stat_statements_1_3'
|
||||||
LANGUAGE C STRICT VOLATILE;
|
LANGUAGE C STRICT VOLATILE;
|
||||||
|
|
||||||
-- Register a view on the function for ease of use.
|
-- Register a view on the function for ease of use.
|
@ -115,7 +115,8 @@ typedef enum pgssVersion
|
|||||||
{
|
{
|
||||||
PGSS_V1_0 = 0,
|
PGSS_V1_0 = 0,
|
||||||
PGSS_V1_1,
|
PGSS_V1_1,
|
||||||
PGSS_V1_2
|
PGSS_V1_2,
|
||||||
|
PGSS_V1_3
|
||||||
} pgssVersion;
|
} pgssVersion;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -136,6 +137,10 @@ typedef struct Counters
|
|||||||
{
|
{
|
||||||
int64 calls; /* # of times executed */
|
int64 calls; /* # of times executed */
|
||||||
double total_time; /* total execution time, in msec */
|
double total_time; /* total execution time, in msec */
|
||||||
|
double min_time; /* minimim execution time in msec */
|
||||||
|
double max_time; /* maximum execution time in msec */
|
||||||
|
double mean_time; /* mean execution time in msec */
|
||||||
|
double sum_var_time; /* sum of variances in execution time in msec */
|
||||||
int64 rows; /* total # of retrieved or affected rows */
|
int64 rows; /* total # of retrieved or affected rows */
|
||||||
int64 shared_blks_hit; /* # of shared buffer hits */
|
int64 shared_blks_hit; /* # of shared buffer hits */
|
||||||
int64 shared_blks_read; /* # of shared disk blocks read */
|
int64 shared_blks_read; /* # of shared disk blocks read */
|
||||||
@ -274,6 +279,7 @@ void _PG_fini(void);
|
|||||||
|
|
||||||
PG_FUNCTION_INFO_V1(pg_stat_statements_reset);
|
PG_FUNCTION_INFO_V1(pg_stat_statements_reset);
|
||||||
PG_FUNCTION_INFO_V1(pg_stat_statements_1_2);
|
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);
|
PG_FUNCTION_INFO_V1(pg_stat_statements);
|
||||||
|
|
||||||
static void pgss_shmem_startup(void);
|
static void pgss_shmem_startup(void);
|
||||||
@ -320,6 +326,7 @@ static char *generate_normalized_query(pgssJumbleState *jstate, const char *quer
|
|||||||
int *query_len_p, int encoding);
|
int *query_len_p, int encoding);
|
||||||
static void fill_in_constant_lengths(pgssJumbleState *jstate, const char *query);
|
static void fill_in_constant_lengths(pgssJumbleState *jstate, const char *query);
|
||||||
static int comp_location(const void *a, const void *b);
|
static int comp_location(const void *a, const void *b);
|
||||||
|
static inline double sqrtd(const double x);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1215,6 +1222,32 @@ pgss_store(const char *query, uint32 queryId,
|
|||||||
|
|
||||||
e->counters.calls += 1;
|
e->counters.calls += 1;
|
||||||
e->counters.total_time += total_time;
|
e->counters.total_time += total_time;
|
||||||
|
if (e->counters.calls == 1)
|
||||||
|
{
|
||||||
|
e->counters.min_time = total_time;
|
||||||
|
e->counters.max_time = total_time;
|
||||||
|
e->counters.mean_time = total_time;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Welford's method for accurately computing variance.
|
||||||
|
* See <http://www.johndcook.com/blog/standard_deviation/>
|
||||||
|
*/
|
||||||
|
double old_mean = e->counters.mean_time;
|
||||||
|
|
||||||
|
e->counters.mean_time +=
|
||||||
|
(total_time - old_mean) / e->counters.calls;
|
||||||
|
e->counters.sum_var_time +=
|
||||||
|
(total_time - old_mean) * (total_time - e->counters.mean_time);
|
||||||
|
|
||||||
|
/* calculate min and max time */
|
||||||
|
if (e->counters.min_time > total_time)
|
||||||
|
e->counters.min_time = total_time;
|
||||||
|
if (e->counters.max_time < total_time)
|
||||||
|
e->counters.max_time = total_time;
|
||||||
|
|
||||||
|
}
|
||||||
e->counters.rows += rows;
|
e->counters.rows += rows;
|
||||||
e->counters.shared_blks_hit += bufusage->shared_blks_hit;
|
e->counters.shared_blks_hit += bufusage->shared_blks_hit;
|
||||||
e->counters.shared_blks_read += bufusage->shared_blks_read;
|
e->counters.shared_blks_read += bufusage->shared_blks_read;
|
||||||
@ -1259,7 +1292,8 @@ pg_stat_statements_reset(PG_FUNCTION_ARGS)
|
|||||||
#define PG_STAT_STATEMENTS_COLS_V1_0 14
|
#define PG_STAT_STATEMENTS_COLS_V1_0 14
|
||||||
#define PG_STAT_STATEMENTS_COLS_V1_1 18
|
#define PG_STAT_STATEMENTS_COLS_V1_1 18
|
||||||
#define PG_STAT_STATEMENTS_COLS_V1_2 19
|
#define PG_STAT_STATEMENTS_COLS_V1_2 19
|
||||||
#define PG_STAT_STATEMENTS_COLS 19 /* maximum of above */
|
#define PG_STAT_STATEMENTS_COLS_V1_3 23
|
||||||
|
#define PG_STAT_STATEMENTS_COLS 23 /* maximum of above */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Retrieve statement statistics.
|
* Retrieve statement statistics.
|
||||||
@ -1271,6 +1305,16 @@ pg_stat_statements_reset(PG_FUNCTION_ARGS)
|
|||||||
* expected API version is identified by embedding it in the C name of the
|
* 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.
|
* function. Unfortunately we weren't bright enough to do that for 1.1.
|
||||||
*/
|
*/
|
||||||
|
Datum
|
||||||
|
pg_stat_statements_1_3(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
bool showtext = PG_GETARG_BOOL(0);
|
||||||
|
|
||||||
|
pg_stat_statements_internal(fcinfo, PGSS_V1_3, showtext);
|
||||||
|
|
||||||
|
return (Datum) 0;
|
||||||
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
pg_stat_statements_1_2(PG_FUNCTION_ARGS)
|
pg_stat_statements_1_2(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
@ -1360,6 +1404,10 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo,
|
|||||||
if (api_version != PGSS_V1_2)
|
if (api_version != PGSS_V1_2)
|
||||||
elog(ERROR, "incorrect number of output arguments");
|
elog(ERROR, "incorrect number of output arguments");
|
||||||
break;
|
break;
|
||||||
|
case PG_STAT_STATEMENTS_COLS_V1_3:
|
||||||
|
if (api_version != PGSS_V1_3)
|
||||||
|
elog(ERROR, "incorrect number of output arguments");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
elog(ERROR, "incorrect number of output arguments");
|
elog(ERROR, "incorrect number of output arguments");
|
||||||
}
|
}
|
||||||
@ -1519,6 +1567,23 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo,
|
|||||||
|
|
||||||
values[i++] = Int64GetDatumFast(tmp.calls);
|
values[i++] = Int64GetDatumFast(tmp.calls);
|
||||||
values[i++] = Float8GetDatumFast(tmp.total_time);
|
values[i++] = Float8GetDatumFast(tmp.total_time);
|
||||||
|
if (api_version >= PGSS_V1_3)
|
||||||
|
{
|
||||||
|
values[i++] = Float8GetDatumFast(tmp.min_time);
|
||||||
|
values[i++] = Float8GetDatumFast(tmp.max_time);
|
||||||
|
values[i++] = Float8GetDatumFast(tmp.mean_time);
|
||||||
|
/*
|
||||||
|
* Note we are calculating the population variance here, not the
|
||||||
|
* sample variance, as we have data for the whole population,
|
||||||
|
* so Bessel's correction is not used, and we don't divide by
|
||||||
|
* tmp.calls - 1.
|
||||||
|
*/
|
||||||
|
if (tmp.calls > 1)
|
||||||
|
values[i++] =
|
||||||
|
Float8GetDatumFast(sqrtd(tmp.sum_var_time / tmp.calls));
|
||||||
|
else
|
||||||
|
values[i++] = Float8GetDatumFast(0.0);
|
||||||
|
}
|
||||||
values[i++] = Int64GetDatumFast(tmp.rows);
|
values[i++] = Int64GetDatumFast(tmp.rows);
|
||||||
values[i++] = Int64GetDatumFast(tmp.shared_blks_hit);
|
values[i++] = Int64GetDatumFast(tmp.shared_blks_hit);
|
||||||
values[i++] = Int64GetDatumFast(tmp.shared_blks_read);
|
values[i++] = Int64GetDatumFast(tmp.shared_blks_read);
|
||||||
@ -1541,6 +1606,7 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo,
|
|||||||
Assert(i == (api_version == PGSS_V1_0 ? PG_STAT_STATEMENTS_COLS_V1_0 :
|
Assert(i == (api_version == PGSS_V1_0 ? PG_STAT_STATEMENTS_COLS_V1_0 :
|
||||||
api_version == PGSS_V1_1 ? PG_STAT_STATEMENTS_COLS_V1_1 :
|
api_version == PGSS_V1_1 ? PG_STAT_STATEMENTS_COLS_V1_1 :
|
||||||
api_version == PGSS_V1_2 ? PG_STAT_STATEMENTS_COLS_V1_2 :
|
api_version == PGSS_V1_2 ? PG_STAT_STATEMENTS_COLS_V1_2 :
|
||||||
|
api_version == PGSS_V1_3 ? PG_STAT_STATEMENTS_COLS_V1_3 :
|
||||||
-1 /* fail if you forget to update this assert */ ));
|
-1 /* fail if you forget to update this assert */ ));
|
||||||
|
|
||||||
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
|
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
|
||||||
@ -2899,3 +2965,20 @@ comp_location(const void *a, const void *b)
|
|||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* fast sqrt algorithm: reference from Fast inverse square root algorithms.
|
||||||
|
*/
|
||||||
|
static inline double
|
||||||
|
sqrtd(const double x)
|
||||||
|
{
|
||||||
|
double x_half = 0.5 * x;
|
||||||
|
long long int tmp = 0x5FE6EB50C7B537AAl - ( *(long long int*)&x >> 1);
|
||||||
|
double x_result = * (double*)&tmp;
|
||||||
|
|
||||||
|
x_result *= (1.5 - (x_half * x_result * x_result));
|
||||||
|
/* If retry this calculation, it becomes higher precision at sqrt */
|
||||||
|
x_result *= (1.5 - (x_half * x_result * x_result));
|
||||||
|
|
||||||
|
return x_result * x;
|
||||||
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# pg_stat_statements extension
|
# pg_stat_statements extension
|
||||||
comment = 'track execution statistics of all SQL statements executed'
|
comment = 'track execution statistics of all SQL statements executed'
|
||||||
default_version = '1.2'
|
default_version = '1.3'
|
||||||
module_pathname = '$libdir/pg_stat_statements'
|
module_pathname = '$libdir/pg_stat_statements'
|
||||||
relocatable = true
|
relocatable = true
|
||||||
|
@ -86,6 +86,34 @@
|
|||||||
<entry>Total time spent in the statement, in milliseconds</entry>
|
<entry>Total time spent in the statement, in milliseconds</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><structfield>min_time</structfield></entry>
|
||||||
|
<entry><type>double precision</type></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>Minimum time spent in the statement, in milliseconds</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><structfield>max_time</structfield></entry>
|
||||||
|
<entry><type>double precision</type></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>Maximum time spent in the statement, in milliseconds</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><structfield>mean_time</structfield></entry>
|
||||||
|
<entry><type>double precision</type></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>Mean time spent in the statement, in milliseconds</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><structfield>stddev_time</structfield></entry>
|
||||||
|
<entry><type>double precision</type></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>Population standard deviation of time spent in the statement, in milliseconds</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry><structfield>rows</structfield></entry>
|
<entry><structfield>rows</structfield></entry>
|
||||||
<entry><type>bigint</type></entry>
|
<entry><type>bigint</type></entry>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user