mirror of https://github.com/postgres/postgres
This patch adds 'stats_since' and 'minmax_stats_since' columns to the pg_stat_statements view and pg_stat_statements() function. The new min/max reset mode for the pg_stat_stetments_reset() function is controlled by the parameter minmax_only. 'stat_since' column is populated with the current timestamp when a new statement is added to the pg_stat_statements hashtable. It provides clean information about statistics collection time intervals for each statement. Besides it can be used by sampling solutions to detect situations when a statement was evicted and stored again between samples. Such a sampling solution could derive any pg_stat_statements statistic values for an interval between two samples with the exception of all min/max statistics. To address this issue this patch adds the ability to reset min/max statistics independently of the statement reset using the new minmax_only parameter of the pg_stat_statements_reset(userid oid, dbid oid, queryid bigint, minmax_only boolean) function. The timestamp of such reset is stored in the minmax_stats_since field for each statement. pg_stat_statements_reset() function now returns the timestamp of a reset as the result. Discussion: https://postgr.es/m/flat/72e80e7b160a6eb189df9ef6f068cce3765d37f8.camel%40moonset.ru Author: Andrei Zubkov Reviewed-by: Julien Rouhaud, Hayato Kuroda, Yuki Seino, Chengxi Sun Reviewed-by: Anton Melnikov, Darren Rush, Michael Paquier, Sergei Kornilov Reviewed-by: Alena Rybakina, Andrei Lepikhovpull/146/head
parent
6ab1dbd26b
commit
dc9f8a7983
@ -0,0 +1,159 @@ |
|||||||
|
-- |
||||||
|
-- statement timestamps |
||||||
|
-- |
||||||
|
-- planning time is needed during tests |
||||||
|
SET pg_stat_statements.track_planning = TRUE; |
||||||
|
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 stats_since >= :'ref_ts', count(*) FROM pg_stat_statements |
||||||
|
WHERE query LIKE '%STMTTS%' |
||||||
|
GROUP BY stats_since >= :'ref_ts' |
||||||
|
ORDER BY stats_since >= :'ref_ts'; |
||||||
|
?column? | count |
||||||
|
----------+------- |
||||||
|
f | 1 |
||||||
|
t | 1 |
||||||
|
(2 rows) |
||||||
|
|
||||||
|
SELECT now() AS ref_ts \gset |
||||||
|
SELECT |
||||||
|
count(*) as total, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE min_plan_time + max_plan_time = 0 |
||||||
|
) as minmax_plan_zero, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE min_exec_time + max_exec_time = 0 |
||||||
|
) as minmax_exec_zero, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE minmax_stats_since >= :'ref_ts' |
||||||
|
) as minmax_stats_since_after_ref, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE stats_since >= :'ref_ts' |
||||||
|
) as stats_since_after_ref |
||||||
|
FROM pg_stat_statements |
||||||
|
WHERE query LIKE '%STMTTS%'; |
||||||
|
total | minmax_plan_zero | minmax_exec_zero | minmax_stats_since_after_ref | stats_since_after_ref |
||||||
|
-------+------------------+------------------+------------------------------+----------------------- |
||||||
|
2 | 0 | 0 | 0 | 0 |
||||||
|
(1 row) |
||||||
|
|
||||||
|
-- Perform single min/max reset |
||||||
|
SELECT pg_stat_statements_reset(0, 0, queryid, true) AS minmax_reset_ts |
||||||
|
FROM pg_stat_statements |
||||||
|
WHERE query LIKE '%STMTTS1%' \gset |
||||||
|
-- check |
||||||
|
SELECT |
||||||
|
count(*) as total, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE min_plan_time + max_plan_time = 0 |
||||||
|
) as minmax_plan_zero, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE min_exec_time + max_exec_time = 0 |
||||||
|
) as minmax_exec_zero, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE minmax_stats_since >= :'ref_ts' |
||||||
|
) as minmax_stats_since_after_ref, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE stats_since >= :'ref_ts' |
||||||
|
) as stats_since_after_ref |
||||||
|
FROM pg_stat_statements |
||||||
|
WHERE query LIKE '%STMTTS%'; |
||||||
|
total | minmax_plan_zero | minmax_exec_zero | minmax_stats_since_after_ref | stats_since_after_ref |
||||||
|
-------+------------------+------------------+------------------------------+----------------------- |
||||||
|
2 | 1 | 1 | 1 | 0 |
||||||
|
(1 row) |
||||||
|
|
||||||
|
-- check minmax reset timestamps |
||||||
|
SELECT |
||||||
|
query, minmax_stats_since = :'minmax_reset_ts' AS reset_ts_match |
||||||
|
FROM pg_stat_statements |
||||||
|
WHERE query LIKE '%STMTTS%' |
||||||
|
ORDER BY query COLLATE "C"; |
||||||
|
query | reset_ts_match |
||||||
|
---------------------------+---------------- |
||||||
|
SELECT $1 AS "STMTTS1" | t |
||||||
|
SELECT $1,$2 AS "STMTTS2" | f |
||||||
|
(2 rows) |
||||||
|
|
||||||
|
-- check that minmax reset does not set stats_reset |
||||||
|
SELECT |
||||||
|
stats_reset = :'minmax_reset_ts' AS stats_reset_ts_match |
||||||
|
FROM pg_stat_statements_info; |
||||||
|
stats_reset_ts_match |
||||||
|
---------------------- |
||||||
|
f |
||||||
|
(1 row) |
||||||
|
|
||||||
|
-- Perform common min/max reset |
||||||
|
SELECT pg_stat_statements_reset(0, 0, 0, true) AS minmax_reset_ts \gset |
||||||
|
-- check again |
||||||
|
SELECT |
||||||
|
count(*) as total, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE min_plan_time + max_plan_time = 0 |
||||||
|
) as minmax_plan_zero, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE min_exec_time + max_exec_time = 0 |
||||||
|
) as minmax_exec_zero, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE minmax_stats_since >= :'ref_ts' |
||||||
|
) as minmax_ts_after_ref, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE minmax_stats_since = :'minmax_reset_ts' |
||||||
|
) as minmax_ts_match, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE stats_since >= :'ref_ts' |
||||||
|
) as stats_since_after_ref |
||||||
|
FROM pg_stat_statements |
||||||
|
WHERE query LIKE '%STMTTS%'; |
||||||
|
total | minmax_plan_zero | minmax_exec_zero | minmax_ts_after_ref | minmax_ts_match | stats_since_after_ref |
||||||
|
-------+------------------+------------------+---------------------+-----------------+----------------------- |
||||||
|
2 | 2 | 2 | 2 | 2 | 0 |
||||||
|
(1 row) |
||||||
|
|
||||||
|
-- Execute first query once more to check stats update |
||||||
|
SELECT 1 AS "STMTTS1"; |
||||||
|
STMTTS1 |
||||||
|
--------- |
||||||
|
1 |
||||||
|
(1 row) |
||||||
|
|
||||||
|
-- check |
||||||
|
-- we don't check planing times here to be independent of |
||||||
|
-- plan caching approach |
||||||
|
SELECT |
||||||
|
count(*) as total, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE min_exec_time + max_exec_time = 0 |
||||||
|
) as minmax_exec_zero, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE minmax_stats_since >= :'ref_ts' |
||||||
|
) as minmax_ts_after_ref, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE stats_since >= :'ref_ts' |
||||||
|
) as stats_since_after_ref |
||||||
|
FROM pg_stat_statements |
||||||
|
WHERE query LIKE '%STMTTS%'; |
||||||
|
total | minmax_exec_zero | minmax_ts_after_ref | stats_since_after_ref |
||||||
|
-------+------------------+---------------------+----------------------- |
||||||
|
2 | 1 | 2 | 0 |
||||||
|
(1 row) |
||||||
|
|
||||||
|
-- Cleanup |
||||||
|
SELECT pg_stat_statements_reset() IS NOT NULL AS t; |
||||||
|
t |
||||||
|
--- |
||||||
|
t |
||||||
|
(1 row) |
||||||
|
|
||||||
@ -0,0 +1,114 @@ |
|||||||
|
-- |
||||||
|
-- statement timestamps |
||||||
|
-- |
||||||
|
|
||||||
|
-- planning time is needed during tests |
||||||
|
SET pg_stat_statements.track_planning = TRUE; |
||||||
|
|
||||||
|
SELECT 1 AS "STMTTS1"; |
||||||
|
SELECT now() AS ref_ts \gset |
||||||
|
SELECT 1,2 AS "STMTTS2"; |
||||||
|
SELECT stats_since >= :'ref_ts', count(*) FROM pg_stat_statements |
||||||
|
WHERE query LIKE '%STMTTS%' |
||||||
|
GROUP BY stats_since >= :'ref_ts' |
||||||
|
ORDER BY stats_since >= :'ref_ts'; |
||||||
|
|
||||||
|
SELECT now() AS ref_ts \gset |
||||||
|
SELECT |
||||||
|
count(*) as total, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE min_plan_time + max_plan_time = 0 |
||||||
|
) as minmax_plan_zero, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE min_exec_time + max_exec_time = 0 |
||||||
|
) as minmax_exec_zero, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE minmax_stats_since >= :'ref_ts' |
||||||
|
) as minmax_stats_since_after_ref, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE stats_since >= :'ref_ts' |
||||||
|
) as stats_since_after_ref |
||||||
|
FROM pg_stat_statements |
||||||
|
WHERE query LIKE '%STMTTS%'; |
||||||
|
|
||||||
|
-- Perform single min/max reset |
||||||
|
SELECT pg_stat_statements_reset(0, 0, queryid, true) AS minmax_reset_ts |
||||||
|
FROM pg_stat_statements |
||||||
|
WHERE query LIKE '%STMTTS1%' \gset |
||||||
|
|
||||||
|
-- check |
||||||
|
SELECT |
||||||
|
count(*) as total, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE min_plan_time + max_plan_time = 0 |
||||||
|
) as minmax_plan_zero, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE min_exec_time + max_exec_time = 0 |
||||||
|
) as minmax_exec_zero, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE minmax_stats_since >= :'ref_ts' |
||||||
|
) as minmax_stats_since_after_ref, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE stats_since >= :'ref_ts' |
||||||
|
) as stats_since_after_ref |
||||||
|
FROM pg_stat_statements |
||||||
|
WHERE query LIKE '%STMTTS%'; |
||||||
|
|
||||||
|
-- check minmax reset timestamps |
||||||
|
SELECT |
||||||
|
query, minmax_stats_since = :'minmax_reset_ts' AS reset_ts_match |
||||||
|
FROM pg_stat_statements |
||||||
|
WHERE query LIKE '%STMTTS%' |
||||||
|
ORDER BY query COLLATE "C"; |
||||||
|
|
||||||
|
-- check that minmax reset does not set stats_reset |
||||||
|
SELECT |
||||||
|
stats_reset = :'minmax_reset_ts' AS stats_reset_ts_match |
||||||
|
FROM pg_stat_statements_info; |
||||||
|
|
||||||
|
-- Perform common min/max reset |
||||||
|
SELECT pg_stat_statements_reset(0, 0, 0, true) AS minmax_reset_ts \gset |
||||||
|
|
||||||
|
-- check again |
||||||
|
SELECT |
||||||
|
count(*) as total, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE min_plan_time + max_plan_time = 0 |
||||||
|
) as minmax_plan_zero, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE min_exec_time + max_exec_time = 0 |
||||||
|
) as minmax_exec_zero, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE minmax_stats_since >= :'ref_ts' |
||||||
|
) as minmax_ts_after_ref, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE minmax_stats_since = :'minmax_reset_ts' |
||||||
|
) as minmax_ts_match, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE stats_since >= :'ref_ts' |
||||||
|
) as stats_since_after_ref |
||||||
|
FROM pg_stat_statements |
||||||
|
WHERE query LIKE '%STMTTS%'; |
||||||
|
|
||||||
|
-- Execute first query once more to check stats update |
||||||
|
SELECT 1 AS "STMTTS1"; |
||||||
|
|
||||||
|
-- check |
||||||
|
-- we don't check planing times here to be independent of |
||||||
|
-- plan caching approach |
||||||
|
SELECT |
||||||
|
count(*) as total, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE min_exec_time + max_exec_time = 0 |
||||||
|
) as minmax_exec_zero, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE minmax_stats_since >= :'ref_ts' |
||||||
|
) as minmax_ts_after_ref, |
||||||
|
count(*) FILTER ( |
||||||
|
WHERE stats_since >= :'ref_ts' |
||||||
|
) as stats_since_after_ref |
||||||
|
FROM pg_stat_statements |
||||||
|
WHERE query LIKE '%STMTTS%'; |
||||||
|
|
||||||
|
-- Cleanup |
||||||
|
SELECT pg_stat_statements_reset() IS NOT NULL AS t; |
||||||
Loading…
Reference in new issue