1
0
mirror of https://github.com/postgres/postgres.git synced 2025-10-31 10:30:33 +03:00
Files
postgres/contrib/pg_stat_statements/expected/select.out
Michael Paquier 787514b30b Use relation name instead of OID in query jumbling for RangeTblEntry
custom_query_jumble (introduced in 5ac462e2b7 as a node field
attribute) is now assigned to the expanded reference name "eref" of
RangeTblEntry, adding in the query jumble computation the non-qualified
aliased relation name, without the list of column names.  The relation
OID is removed from the query jumbling.

The effects of this change can be seen in the tests added by
3430215fe3, where pg_stat_statements (PGSS) entries are now grouped
using the relation name, ignoring the relation search_path may point at.
For example, these two relations are different, but are now grouped in a
single PGSS entry as they are assigned the same query ID:
CREATE TABLE foo1.tab (a int);
CREATE TABLE foo2.tab (b int);
SET search_path = 'foo1';
SELECT count(*) FROM tab;
SET search_path = 'foo2';
SELECT count(*) FROM tab;
SELECT count(*) FROM foo1.tab;
SELECT count(*) FROM foo2.tab;
SELECT query, calls FROM pg_stat_statements WHERE query ~ 'FROM tab';
          query           | calls
--------------------------+-------
 SELECT count(*) FROM tab |     4
(1 row)

It is still possible to use an alias in the FROM clause to split these.
This behavior is useful for relations re-created with the same name,
where queries based on such relations would be grouped in the same
PGSS entry.  For permanent schemas, it should not really matter in
practice.  The main benefit is for workloads that use a lot of temporary
relations, which are usually re-created with the same name continuously.
These can be a heavy source of bloat in PGSS depending on the workload.
Such entries can now be grouped together, improving the user experience.

The original idea from Christoph Berg used catalog lookups to find
temporary relations, something that the query jumble has never done, and
it could cause some performance regressions.  The idea to use
RangeTblEntry.eref and the relation name, applying the same rules for
all relations, temporary and not temporary, has been proposed by Tom
Lane.  The documentation additions have been suggested by Sami Imseih.

Author: Michael Paquier <michael@paquier.xyz>
Co-authored-by: Sami Imseih <samimseih@gmail.com>
Reviewed-by: Christoph Berg <myon@debian.org>
Reviewed-by: Lukas Fittl <lukas@fittl.com>
Reviewed-by: Sami Imseih <samimseih@gmail.com>
Discussion: https://postgr.es/m/Z9iWXKGwkm8RAC93@msg.df7cb.de
2025-03-26 15:21:05 +09:00

652 lines
13 KiB
Plaintext

--
-- SELECT statements
--
CREATE EXTENSION pg_stat_statements;
SET pg_stat_statements.track_utility = FALSE;
SET pg_stat_statements.track_planning = TRUE;
SELECT pg_stat_statements_reset() IS NOT NULL AS t;
t
---
t
(1 row)
--
-- simple and compound statements
--
SELECT 1 AS "int";
int
-----
1
(1 row)
/* this comment should not appear in the output */
SELECT 'hello'
-- but this one will appear
AS "text";
text
-------
hello
(1 row)
SELECT 'world' AS "text";
text
-------
world
(1 row)
-- transaction
BEGIN;
SELECT 1 AS "int";
int
-----
1
(1 row)
SELECT 'hello' AS "text";
text
-------
hello
(1 row)
COMMIT;
-- compound transaction
BEGIN \;
SELECT 2.0 AS "float" \;
SELECT 'world' AS "text" \;
COMMIT;
float
-------
2.0
(1 row)
text
-------
world
(1 row)
-- compound with empty statements and spurious leading spacing
\;\; SELECT 3 + 3 \;\;\; SELECT ' ' || ' !' \;\; SELECT 1 + 4 \;;
?column?
----------
6
(1 row)
?column?
----------
!
(1 row)
?column?
----------
5
(1 row)
-- non ;-terminated statements
SELECT 1 + 1 + 1 AS "add" \gset
SELECT :add + 1 + 1 AS "add" \;
SELECT :add + 1 + 1 AS "add" \gset
add
-----
5
(1 row)
-- set operator
SELECT 1 AS i UNION SELECT 2 ORDER BY i;
i
---
1
2
(2 rows)
-- ? operator
select '{"a":1, "b":2}'::jsonb ? 'b';
?column?
----------
t
(1 row)
-- cte
WITH t(f) AS (
VALUES (1.0), (2.0)
)
SELECT f FROM t ORDER BY f;
f
-----
1.0
2.0
(2 rows)
-- prepared statement with parameter
PREPARE pgss_test (int) AS SELECT $1, 'test' LIMIT 1;
EXECUTE pgss_test(1);
?column? | ?column?
----------+----------
1 | test
(1 row)
DEALLOCATE pgss_test;
SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
calls | rows | query
-------+------+------------------------------------------------------------------------------
4 | 4 | SELECT $1 +
| | -- but this one will appear +
| | AS "text"
2 | 2 | SELECT $1 + $2
3 | 3 | SELECT $1 + $2 + $3 AS "add"
1 | 1 | SELECT $1 AS "float"
2 | 2 | SELECT $1 AS "int"
1 | 2 | SELECT $1 AS i UNION SELECT $2 ORDER BY i
1 | 1 | SELECT $1 || $2
1 | 1 | SELECT $1, $2 LIMIT $3
0 | 0 | SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C"
1 | 1 | SELECT pg_stat_statements_reset() IS NOT NULL AS t
1 | 2 | WITH t(f) AS ( +
| | VALUES ($1), ($2) +
| | ) +
| | SELECT f FROM t ORDER BY f
1 | 1 | select $1::jsonb ? $2
(12 rows)
SELECT pg_stat_statements_reset() IS NOT NULL AS t;
t
---
t
(1 row)
--
-- queries with locking clauses
--
CREATE TABLE pgss_a (id integer PRIMARY KEY);
CREATE TABLE pgss_b (id integer PRIMARY KEY, a_id integer REFERENCES pgss_a);
SELECT pg_stat_statements_reset() IS NOT NULL AS t;
t
---
t
(1 row)
-- control query
SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id;
id | id | a_id
----+----+------
(0 rows)
-- test range tables
SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE;
id | id | a_id
----+----+------
(0 rows)
SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_a;
id | id | a_id
----+----+------
(0 rows)
SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_b;
id | id | a_id
----+----+------
(0 rows)
SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_a, pgss_b; -- matches plain "FOR UPDATE"
id | id | a_id
----+----+------
(0 rows)
SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_b, pgss_a;
id | id | a_id
----+----+------
(0 rows)
-- test strengths
SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR NO KEY UPDATE;
id | id | a_id
----+----+------
(0 rows)
SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR SHARE;
id | id | a_id
----+----+------
(0 rows)
SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR KEY SHARE;
id | id | a_id
----+----+------
(0 rows)
-- test wait policies
SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE NOWAIT;
id | id | a_id
----+----+------
(0 rows)
SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE SKIP LOCKED;
id | id | a_id
----+----+------
(0 rows)
SELECT calls, query FROM pg_stat_statements ORDER BY query COLLATE "C";
calls | query
-------+------------------------------------------------------------------------------------------
1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id
1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR KEY SHARE
1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR NO KEY UPDATE
1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR SHARE
2 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE
1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE NOWAIT
1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_a
1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_b
1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_b, pgss_a
1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE SKIP LOCKED
0 | SELECT calls, query FROM pg_stat_statements ORDER BY query COLLATE "C"
1 | SELECT pg_stat_statements_reset() IS NOT NULL AS t
(12 rows)
DROP TABLE pgss_a, pgss_b CASCADE;
--
-- access to pg_stat_statements_info view
--
SELECT pg_stat_statements_reset() IS NOT NULL AS t;
t
---
t
(1 row)
SELECT dealloc FROM pg_stat_statements_info;
dealloc
---------
0
(1 row)
-- FROM [ONLY]
CREATE TABLE tbl_inh(id integer);
CREATE TABLE tbl_inh_1() INHERITS (tbl_inh);
INSERT INTO tbl_inh_1 SELECT 1;
SELECT * FROM tbl_inh;
id
----
1
(1 row)
SELECT * FROM ONLY tbl_inh;
id
----
(0 rows)
SELECT COUNT(*) FROM pg_stat_statements WHERE query LIKE '%FROM%tbl_inh%';
count
-------
2
(1 row)
-- WITH TIES
CREATE TABLE limitoption AS SELECT 0 AS val FROM generate_series(1, 10);
SELECT *
FROM limitoption
WHERE val < 2
ORDER BY val
FETCH FIRST 2 ROWS WITH TIES;
val
-----
0
0
0
0
0
0
0
0
0
0
(10 rows)
SELECT *
FROM limitoption
WHERE val < 2
ORDER BY val
FETCH FIRST 2 ROW ONLY;
val
-----
0
0
(2 rows)
SELECT COUNT(*) FROM pg_stat_statements WHERE query LIKE '%FETCH FIRST%';
count
-------
2
(1 row)
-- GROUP BY [DISTINCT]
SELECT a, b, c
FROM (VALUES (1, 2, 3), (4, NULL, 6), (7, 8, 9)) AS t (a, b, c)
GROUP BY ROLLUP(a, b), rollup(a, c)
ORDER BY a, b, c;
a | b | c
---+---+---
1 | 2 | 3
1 | 2 |
1 | 2 |
1 | | 3
1 | | 3
1 | |
1 | |
1 | |
4 | | 6
4 | | 6
4 | | 6
4 | |
4 | |
4 | |
4 | |
4 | |
7 | 8 | 9
7 | 8 |
7 | 8 |
7 | | 9
7 | | 9
7 | |
7 | |
7 | |
| |
(25 rows)
SELECT a, b, c
FROM (VALUES (1, 2, 3), (4, NULL, 6), (7, 8, 9)) AS t (a, b, c)
GROUP BY DISTINCT ROLLUP(a, b), rollup(a, c)
ORDER BY a, b, c;
a | b | c
---+---+---
1 | 2 | 3
1 | 2 |
1 | | 3
1 | |
4 | | 6
4 | | 6
4 | |
4 | |
7 | 8 | 9
7 | 8 |
7 | | 9
7 | |
| |
(13 rows)
SELECT COUNT(*) FROM pg_stat_statements WHERE query LIKE '%GROUP BY%ROLLUP%';
count
-------
2
(1 row)
-- GROUPING SET agglevelsup
SELECT (
SELECT (
SELECT GROUPING(a,b) FROM (VALUES (1)) v2(c)
) FROM (VALUES (1,2)) v1(a,b) GROUP BY (a,b)
) FROM (VALUES(6,7)) v3(e,f) GROUP BY ROLLUP(e,f);
grouping
----------
0
0
0
(3 rows)
SELECT (
SELECT (
SELECT GROUPING(e,f) FROM (VALUES (1)) v2(c)
) FROM (VALUES (1,2)) v1(a,b) GROUP BY (a,b)
) FROM (VALUES(6,7)) v3(e,f) GROUP BY ROLLUP(e,f);
grouping
----------
3
0
1
(3 rows)
SELECT COUNT(*) FROM pg_stat_statements WHERE query LIKE '%SELECT GROUPING%';
count
-------
2
(1 row)
SELECT pg_stat_statements_reset() IS NOT NULL AS t;
t
---
t
(1 row)
-- Temporary table with same name, re-created.
BEGIN;
CREATE TEMP TABLE temp_t (id int) ON COMMIT DROP;
SELECT * FROM temp_t;
id
----
(0 rows)
COMMIT;
BEGIN;
CREATE TEMP TABLE temp_t (id int) ON COMMIT DROP;
SELECT * FROM temp_t;
id
----
(0 rows)
COMMIT;
SELECT calls, query FROM pg_stat_statements ORDER BY query COLLATE "C";
calls | query
-------+------------------------------------------------------------------------
2 | SELECT * FROM temp_t
0 | SELECT calls, query FROM pg_stat_statements ORDER BY query COLLATE "C"
1 | SELECT pg_stat_statements_reset() IS NOT NULL AS t
(3 rows)
SELECT pg_stat_statements_reset() IS NOT NULL AS t;
t
---
t
(1 row)
-- search_path with various schemas and temporary tables
CREATE SCHEMA pgss_schema_1;
CREATE SCHEMA pgss_schema_2;
-- Same attributes.
CREATE TABLE pgss_schema_1.tab_search_same (a int, b int);
CREATE TABLE pgss_schema_2.tab_search_same (a int, b int);
CREATE TEMP TABLE tab_search_same (a int, b int);
-- Different number of attributes, mapping types
CREATE TABLE pgss_schema_1.tab_search_diff_1 (a int);
CREATE TABLE pgss_schema_2.tab_search_diff_1 (a int, b int);
CREATE TEMP TABLE tab_search_diff_1 (a int, b int, c int);
-- Same number of attributes, different types
CREATE TABLE pgss_schema_1.tab_search_diff_2 (a int);
CREATE TABLE pgss_schema_2.tab_search_diff_2 (a text);
CREATE TEMP TABLE tab_search_diff_2 (a bigint);
-- First permanent schema
SET search_path = 'pgss_schema_1';
SELECT count(*) FROM tab_search_same;
count
-------
0
(1 row)
SELECT a, b FROM tab_search_same;
a | b
---+---
(0 rows)
SELECT count(*) FROM tab_search_diff_1;
count
-------
0
(1 row)
SELECT count(*) FROM tab_search_diff_2;
count
-------
0
(1 row)
SELECT a FROM tab_search_diff_2 AS t1;
a
---
(0 rows)
SELECT a FROM tab_search_diff_2;
a
---
(0 rows)
SELECT a AS a1 FROM tab_search_diff_2;
a1
----
(0 rows)
-- Second permanent schema
SET search_path = 'pgss_schema_2';
SELECT count(*) FROM tab_search_same;
count
-------
0
(1 row)
SELECT a, b FROM tab_search_same;
a | b
---+---
(0 rows)
SELECT count(*) FROM tab_search_diff_1;
count
-------
0
(1 row)
SELECT count(*) FROM tab_search_diff_2;
count
-------
0
(1 row)
SELECT a FROM tab_search_diff_2 AS t1;
a
---
(0 rows)
SELECT a FROM tab_search_diff_2;
a
---
(0 rows)
SELECT a AS a1 FROM tab_search_diff_2;
a1
----
(0 rows)
-- Temporary schema
SET search_path = 'pg_temp';
SELECT count(*) FROM tab_search_same;
count
-------
0
(1 row)
SELECT a, b FROM tab_search_same;
a | b
---+---
(0 rows)
SELECT count(*) FROM tab_search_diff_1;
count
-------
0
(1 row)
SELECT count(*) FROM tab_search_diff_2;
count
-------
0
(1 row)
SELECT a FROM tab_search_diff_2 AS t1;
a
---
(0 rows)
SELECT a FROM tab_search_diff_2;
a
---
(0 rows)
SELECT a AS a1 FROM tab_search_diff_2;
a1
----
(0 rows)
RESET search_path;
-- Schema qualifications
SELECT count(*) FROM pgss_schema_1.tab_search_same;
count
-------
0
(1 row)
SELECT a, b FROM pgss_schema_1.tab_search_same;
a | b
---+---
(0 rows)
SELECT count(*) FROM pgss_schema_2.tab_search_diff_1;
count
-------
0
(1 row)
SELECT count(*) FROM pg_temp.tab_search_diff_2;
count
-------
0
(1 row)
SELECT a FROM pgss_schema_2.tab_search_diff_2 AS t1;
a
---
(0 rows)
SELECT a FROM pgss_schema_2.tab_search_diff_2;
a
---
(0 rows)
SELECT a AS a1 FROM pgss_schema_2.tab_search_diff_2;
a1
----
(0 rows)
SELECT calls, query FROM pg_stat_statements ORDER BY query COLLATE "C";
calls | query
-------+------------------------------------------------------------------------
8 | SELECT a FROM tab_search_diff_2
4 | SELECT a FROM tab_search_diff_2 AS t1
4 | SELECT a, b FROM tab_search_same
0 | SELECT calls, query FROM pg_stat_statements ORDER BY query COLLATE "C"
4 | SELECT count(*) FROM tab_search_diff_1
4 | SELECT count(*) FROM tab_search_diff_2
4 | SELECT count(*) FROM tab_search_same
1 | SELECT pg_stat_statements_reset() IS NOT NULL AS t
(8 rows)
DROP SCHEMA pgss_schema_1 CASCADE;
NOTICE: drop cascades to 3 other objects
DETAIL: drop cascades to table pgss_schema_1.tab_search_same
drop cascades to table pgss_schema_1.tab_search_diff_1
drop cascades to table pgss_schema_1.tab_search_diff_2
DROP SCHEMA pgss_schema_2 CASCADE;
NOTICE: drop cascades to 3 other objects
DETAIL: drop cascades to table pgss_schema_2.tab_search_same
drop cascades to table pgss_schema_2.tab_search_diff_1
drop cascades to table pgss_schema_2.tab_search_diff_2
DROP TABLE tab_search_same, tab_search_diff_1, tab_search_diff_2;
SELECT pg_stat_statements_reset() IS NOT NULL AS t;
t
---
t
(1 row)