Skip to content

Commit cd866ff

Browse files
committed
Ignore statements that have no query id
Match pg_stat_statements behavior and ignore statements without query id. Otherwise all such statements stats will be merged into single entry as query id part of the hash key.
1 parent 290192b commit cd866ff

7 files changed

Lines changed: 138 additions & 10 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
- Race condition where we could leak memory for the parent query
4242
- `plans` now counts only actual planner invocations instead of every execution: utility statements and executions that reuse a cached plan no longer bump the counter
4343
- Normalize the query text of utility statements ([PG-2623](https://perconadev.atlassian.net/browse/PG-2623))
44+
- Ignore statements that have no query id
4445

4546
## [2.3.2] - 2026-03-02
4647

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ REGRESS = basic \
1717
version \
1818
guc \
1919
pgsm_query_id \
20+
query_id \
2021
functions \
2122
counters \
2223
relations \

regression/expected/level_tracking_4.out

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,11 @@ SELECT pg_stat_monitor_reset();
100100
CALL proc_with_utility_stmt();
101101
SELECT toplevel, calls, query FROM pg_stat_monitor
102102
ORDER BY query COLLATE "C", toplevel;
103-
toplevel | calls | query
104-
----------+-------+---------------------------------
103+
toplevel | calls | query
104+
----------+-------+--------------------------------
105105
t | 1 | CALL proc_with_utility_stmt()
106106
t | 1 | SELECT pg_stat_monitor_reset()
107-
f | 3 | SHOW pg_stat_monitor.pgsm_track
108-
(3 rows)
107+
(2 rows)
109108

110109
-- top-level tracking.
111110
SET pg_stat_monitor.pgsm_track = 'top';

regression/expected/level_tracking_5.out

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,11 @@ SELECT pg_stat_monitor_reset();
100100
CALL proc_with_utility_stmt();
101101
SELECT toplevel, calls, query FROM pg_stat_monitor
102102
ORDER BY query COLLATE "C", toplevel;
103-
toplevel | calls | query
104-
----------+-------+---------------------------------
103+
toplevel | calls | query
104+
----------+-------+--------------------------------
105105
t | 1 | CALL proc_with_utility_stmt()
106106
t | 1 | SELECT pg_stat_monitor_reset()
107-
f | 3 | SHOW pg_stat_monitor.pgsm_track
108-
(3 rows)
107+
(2 rows)
109108

110109
-- top-level tracking.
111110
SET pg_stat_monitor.pgsm_track = 'top';

regression/expected/query_id.out

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
CREATE EXTENSION pg_stat_monitor;
2+
SET pg_stat_monitor.pgsm_track_utility = on;
3+
SET pg_stat_monitor.pgsm_track_planning = on;
4+
SET pg_stat_monitor.pgsm_normalized_query = on;
5+
--
6+
-- Do not store queries without a query identifier
7+
--
8+
SET compute_query_id = off;
9+
SELECT pg_stat_monitor_reset() IS NOT NULL AS t;
10+
t
11+
---
12+
t
13+
(1 row)
14+
15+
SELECT 1 AS no_query_id;
16+
no_query_id
17+
-------------
18+
1
19+
(1 row)
20+
21+
CREATE TABLE no_query_id_tab (x int);
22+
INSERT INTO no_query_id_tab VALUES (1);
23+
SELECT x FROM no_query_id_tab;
24+
x
25+
---
26+
1
27+
(1 row)
28+
29+
PREPARE no_query_id_prep AS SELECT x FROM no_query_id_tab WHERE x = $1;
30+
EXECUTE no_query_id_prep(1);
31+
x
32+
---
33+
1
34+
(1 row)
35+
36+
DEALLOCATE no_query_id_prep;
37+
DROP TABLE no_query_id_tab;
38+
DO $$
39+
BEGIN
40+
PERFORM 1;
41+
END
42+
$$;
43+
-- Nothing of the above was recorded.
44+
SELECT count(*) FROM pg_stat_monitor;
45+
count
46+
-------
47+
0
48+
(1 row)
49+
50+
--
51+
-- Tracking resumes once query identifiers are computed again.
52+
--
53+
RESET compute_query_id;
54+
SELECT pg_stat_monitor_reset() IS NOT NULL AS t;
55+
t
56+
---
57+
t
58+
(1 row)
59+
60+
SELECT 1 AS with_query_id;
61+
with_query_id
62+
---------------
63+
1
64+
(1 row)
65+
66+
SELECT calls, query FROM pg_stat_monitor
67+
WHERE query LIKE '%with_query_id%' ORDER BY query COLLATE "C";
68+
calls | query
69+
-------+----------------------------
70+
1 | SELECT $1 AS with_query_id
71+
(1 row)
72+
73+
SELECT pg_stat_monitor_reset() IS NOT NULL AS t;
74+
t
75+
---
76+
t
77+
(1 row)
78+
79+
DROP EXTENSION pg_stat_monitor;

regression/sql/query_id.sql

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
CREATE EXTENSION pg_stat_monitor;
2+
SET pg_stat_monitor.pgsm_track_utility = on;
3+
SET pg_stat_monitor.pgsm_track_planning = on;
4+
SET pg_stat_monitor.pgsm_normalized_query = on;
5+
6+
--
7+
-- Do not store queries without a query identifier
8+
--
9+
SET compute_query_id = off;
10+
SELECT pg_stat_monitor_reset() IS NOT NULL AS t;
11+
SELECT 1 AS no_query_id;
12+
CREATE TABLE no_query_id_tab (x int);
13+
INSERT INTO no_query_id_tab VALUES (1);
14+
SELECT x FROM no_query_id_tab;
15+
PREPARE no_query_id_prep AS SELECT x FROM no_query_id_tab WHERE x = $1;
16+
EXECUTE no_query_id_prep(1);
17+
DEALLOCATE no_query_id_prep;
18+
DROP TABLE no_query_id_tab;
19+
DO $$
20+
BEGIN
21+
PERFORM 1;
22+
END
23+
$$;
24+
-- Nothing of the above was recorded.
25+
SELECT count(*) FROM pg_stat_monitor;
26+
27+
--
28+
-- Tracking resumes once query identifiers are computed again.
29+
--
30+
RESET compute_query_id;
31+
SELECT pg_stat_monitor_reset() IS NOT NULL AS t;
32+
SELECT 1 AS with_query_id;
33+
SELECT calls, query FROM pg_stat_monitor
34+
WHERE query LIKE '%with_query_id%' ORDER BY query COLLATE "C";
35+
36+
SELECT pg_stat_monitor_reset() IS NOT NULL AS t;
37+
DROP EXTENSION pg_stat_monitor;

src/pg_stat_monitor.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,13 @@ pgsm_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate)
457457
if (!pgsm_enabled(nesting_level))
458458
return;
459459

460+
/*
461+
* Nothing to do if compute_query_id isn't enabled and no other module
462+
* computed a query identifier.
463+
*/
464+
if (query->queryId == INT64CONST(0))
465+
return;
466+
460467
/*
461468
* If it's EXECUTE, clear the queryId so that stats will accumulate for
462469
* the underlying PREPARE. But don't do this if we're not tracking
@@ -507,8 +514,6 @@ pgsm_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate)
507514
if (query->utilityStmt && norm_query == NULL)
508515
return;
509516

510-
Assert(query->queryId != INT64CONST(0));
511-
512517
/*
513518
* pgsm_query_id always groups by the normalized form when we have one.
514519
* But what gets stored as query text depends on the pgsm_normalized_query
@@ -1806,6 +1811,13 @@ pgsm_store(const pgsmQueryStats *stats)
18061811
if (!IsSystemInitialized())
18071812
return;
18081813

1814+
/*
1815+
* Nothing to do if compute_query_id isn't enabled and no other module
1816+
* computed a query identifier.
1817+
*/
1818+
if (key.queryid == INT64CONST(0))
1819+
return;
1820+
18091821
pgsm = pgsm_get_ss();
18101822

18111823
key.bucket_id = get_next_wbucket(pgsm);

0 commit comments

Comments
 (0)