Teach pg_stat_statements not to ignore FOR UPDATE clauses
Performance of a SELECT FOR UPDATE may be quite distinct from the non-UPDATE version of the query, so treat all of the FOR UPDATE clause as being significant for distinguishing queries. Andrew Gierth and Vik Fearing, reviewed by Sergei Kornilov, Thomas Munro, Tom Lane Discussion: https://postgr.es/m/87h8e4hfwv.fsf@news-spur.riddles.org.uk
This commit is contained in:
parent
0369f47366
commit
6e74c64bcf
@ -354,6 +354,93 @@ SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
|
||||
SELECT pg_stat_statements_reset() | 1 | 1
|
||||
(5 rows)
|
||||
|
||||
--
|
||||
-- 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();
|
||||
pg_stat_statements_reset
|
||||
--------------------------
|
||||
|
||||
(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
|
||||
1 | SELECT pg_stat_statements_reset()
|
||||
(11 rows)
|
||||
|
||||
DROP TABLE pgss_a, pgss_b CASCADE;
|
||||
--
|
||||
-- utility commands
|
||||
--
|
||||
|
@ -333,6 +333,7 @@ static void AppendJumble(pgssJumbleState *jstate,
|
||||
const unsigned char *item, Size size);
|
||||
static void JumbleQuery(pgssJumbleState *jstate, Query *query);
|
||||
static void JumbleRangeTable(pgssJumbleState *jstate, List *rtable);
|
||||
static void JumbleRowMarks(pgssJumbleState *jstate, List *rowMarks);
|
||||
static void JumbleExpr(pgssJumbleState *jstate, Node *node);
|
||||
static void RecordConstLocation(pgssJumbleState *jstate, int location);
|
||||
static char *generate_normalized_query(pgssJumbleState *jstate, const char *query,
|
||||
@ -2430,7 +2431,7 @@ JumbleQuery(pgssJumbleState *jstate, Query *query)
|
||||
JumbleExpr(jstate, (Node *) query->sortClause);
|
||||
JumbleExpr(jstate, query->limitOffset);
|
||||
JumbleExpr(jstate, query->limitCount);
|
||||
/* we ignore rowMarks */
|
||||
JumbleRowMarks(jstate, query->rowMarks);
|
||||
JumbleExpr(jstate, query->setOperations);
|
||||
}
|
||||
|
||||
@ -2489,6 +2490,26 @@ JumbleRangeTable(pgssJumbleState *jstate, List *rtable)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Jumble a rowMarks list
|
||||
*/
|
||||
static void
|
||||
JumbleRowMarks(pgssJumbleState *jstate, List *rowMarks)
|
||||
{
|
||||
ListCell *lc;
|
||||
|
||||
foreach(lc, rowMarks)
|
||||
{
|
||||
RowMarkClause *rowmark = lfirst_node(RowMarkClause, lc);
|
||||
if (!rowmark->pushedDown)
|
||||
{
|
||||
APP_JUMB(rowmark->rti);
|
||||
APP_JUMB(rowmark->strength);
|
||||
APP_JUMB(rowmark->waitPolicy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Jumble an expression tree
|
||||
*
|
||||
|
@ -177,6 +177,37 @@ SELECT PLUS_ONE(1);
|
||||
|
||||
SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
|
||||
|
||||
--
|
||||
-- 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();
|
||||
|
||||
-- control query
|
||||
SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id;
|
||||
|
||||
-- test range tables
|
||||
SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE;
|
||||
SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_a;
|
||||
SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_b;
|
||||
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"
|
||||
SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_b, pgss_a;
|
||||
|
||||
-- test strengths
|
||||
SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR NO KEY UPDATE;
|
||||
SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR SHARE;
|
||||
SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR KEY SHARE;
|
||||
|
||||
-- test wait policies
|
||||
SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE NOWAIT;
|
||||
SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE SKIP LOCKED;
|
||||
|
||||
SELECT calls, query FROM pg_stat_statements ORDER BY query COLLATE "C";
|
||||
|
||||
DROP TABLE pgss_a, pgss_b CASCADE;
|
||||
|
||||
--
|
||||
-- utility commands
|
||||
--
|
||||
|
Loading…
x
Reference in New Issue
Block a user