mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-02-17 19:30:00 +08:00
Allow pg_stat_statements to track WAL usage statistics.
This commit adds three new columns in pg_stat_statements output to display WAL usage statistics added by commitdf3b181499
. This commit doesn't bump the version of pg_stat_statements as the same is done for this release in commit17e0328224
. Author: Kirill Bychik and Julien Rouhaud Reviewed-by: Julien Rouhaud, Fujii Masao, Dilip Kumar and Amit Kapila Discussion: https://postgr.es/m/CAB-hujrP8ZfUkvL5OYETipQwA=e3n7oqHFU=4ZLxWS_Cza3kQQ@mail.gmail.com
This commit is contained in:
parent
70de4e950c
commit
6b466bf5f2
@ -211,6 +211,45 @@ SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
|
||||
UPDATE test SET b = $1 WHERE a > $2 | 1 | 3
|
||||
(10 rows)
|
||||
|
||||
--
|
||||
-- INSERT, UPDATE, DELETE on test table to validate WAL generation metrics
|
||||
--
|
||||
SELECT pg_stat_statements_reset();
|
||||
pg_stat_statements_reset
|
||||
--------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
-- utility "create table" should not be shown
|
||||
CREATE TABLE pgss_test (a int, b char(20));
|
||||
INSERT INTO pgss_test VALUES(generate_series(1, 10), 'aaa');
|
||||
UPDATE pgss_test SET b = 'bbb' WHERE a > 7;
|
||||
DELETE FROM pgss_test WHERE a > 9;
|
||||
-- DROP test table
|
||||
SET pg_stat_statements.track_utility = TRUE;
|
||||
DROP TABLE pgss_test;
|
||||
SET pg_stat_statements.track_utility = FALSE;
|
||||
-- Check WAL is generated for the above statements
|
||||
SELECT query, calls, rows,
|
||||
wal_bytes > 0 as wal_bytes_generated,
|
||||
wal_records > 0 as wal_records_generated,
|
||||
wal_records = rows as wal_records_as_rows
|
||||
FROM pg_stat_statements ORDER BY query COLLATE "C";
|
||||
query | calls | rows | wal_bytes_generated | wal_records_generated | wal_records_as_rows
|
||||
-----------------------------------------------------------+-------+------+---------------------+-----------------------+---------------------
|
||||
DELETE FROM pgss_test WHERE a > $1 | 1 | 1 | t | t | t
|
||||
DROP TABLE pgss_test | 1 | 0 | t | t | f
|
||||
INSERT INTO pgss_test VALUES(generate_series($1, $2), $3) | 1 | 10 | t | t | t
|
||||
SELECT pg_stat_statements_reset() | 1 | 1 | f | f | f
|
||||
SELECT query, calls, rows, +| 0 | 0 | f | f | t
|
||||
wal_bytes > $1 as wal_bytes_generated, +| | | | |
|
||||
wal_records > $2 as wal_records_generated, +| | | | |
|
||||
wal_records = rows as wal_records_as_rows +| | | | |
|
||||
FROM pg_stat_statements ORDER BY query COLLATE "C" | | | | |
|
||||
SET pg_stat_statements.track_utility = FALSE | 1 | 0 | f | f | t
|
||||
UPDATE pgss_test SET b = $1 WHERE a > $2 | 1 | 3 | t | t | t
|
||||
(7 rows)
|
||||
|
||||
--
|
||||
-- pg_stat_statements.track = none
|
||||
--
|
||||
|
@ -41,7 +41,10 @@ CREATE FUNCTION pg_stat_statements(IN showtext boolean,
|
||||
OUT temp_blks_read int8,
|
||||
OUT temp_blks_written int8,
|
||||
OUT blk_read_time float8,
|
||||
OUT blk_write_time float8
|
||||
OUT blk_write_time float8,
|
||||
OUT wal_records int8,
|
||||
OUT wal_num_fpw int8,
|
||||
OUT wal_bytes numeric
|
||||
)
|
||||
RETURNS SETOF record
|
||||
AS 'MODULE_PATHNAME', 'pg_stat_statements_1_8'
|
||||
|
@ -188,6 +188,9 @@ typedef struct Counters
|
||||
double blk_read_time; /* time spent reading, in msec */
|
||||
double blk_write_time; /* time spent writing, in msec */
|
||||
double usage; /* usage factor */
|
||||
int64 wal_records; /* # of WAL records generated */
|
||||
int64 wal_num_fpw; /* # of WAL full page image records generated */
|
||||
uint64 wal_bytes; /* total amount of WAL bytes generated */
|
||||
} Counters;
|
||||
|
||||
/*
|
||||
@ -348,6 +351,7 @@ static void pgss_store(const char *query, uint64 queryId,
|
||||
pgssStoreKind kind,
|
||||
double total_time, uint64 rows,
|
||||
const BufferUsage *bufusage,
|
||||
const WalUsage *walusage,
|
||||
pgssJumbleState *jstate);
|
||||
static void pg_stat_statements_internal(FunctionCallInfo fcinfo,
|
||||
pgssVersion api_version,
|
||||
@ -891,6 +895,7 @@ pgss_post_parse_analyze(ParseState *pstate, Query *query)
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
&jstate);
|
||||
}
|
||||
|
||||
@ -926,9 +931,17 @@ pgss_planner(Query *parse,
|
||||
instr_time duration;
|
||||
BufferUsage bufusage_start,
|
||||
bufusage;
|
||||
WalUsage walusage_start,
|
||||
walusage;
|
||||
|
||||
/* We need to track buffer usage as the planner can access them. */
|
||||
bufusage_start = pgBufferUsage;
|
||||
|
||||
/*
|
||||
* Similarly the planner could write some WAL records in some cases
|
||||
* (e.g. setting a hint bit with those being WAL-logged)
|
||||
*/
|
||||
walusage_start = pgWalUsage;
|
||||
INSTR_TIME_SET_CURRENT(start);
|
||||
|
||||
plan_nested_level++;
|
||||
@ -954,6 +967,10 @@ pgss_planner(Query *parse,
|
||||
memset(&bufusage, 0, sizeof(BufferUsage));
|
||||
BufferUsageAccumDiff(&bufusage, &pgBufferUsage, &bufusage_start);
|
||||
|
||||
/* calc differences of WAL counters. */
|
||||
memset(&walusage, 0, sizeof(WalUsage));
|
||||
WalUsageAccumDiff(&walusage, &pgWalUsage, &walusage_start);
|
||||
|
||||
pgss_store(query_string,
|
||||
parse->queryId,
|
||||
parse->stmt_location,
|
||||
@ -962,6 +979,7 @@ pgss_planner(Query *parse,
|
||||
INSTR_TIME_GET_MILLISEC(duration),
|
||||
0,
|
||||
&bufusage,
|
||||
&walusage,
|
||||
NULL);
|
||||
}
|
||||
else
|
||||
@ -1079,6 +1097,7 @@ pgss_ExecutorEnd(QueryDesc *queryDesc)
|
||||
queryDesc->totaltime->total * 1000.0, /* convert to msec */
|
||||
queryDesc->estate->es_processed,
|
||||
&queryDesc->totaltime->bufusage,
|
||||
&queryDesc->totaltime->walusage,
|
||||
NULL);
|
||||
}
|
||||
|
||||
@ -1123,8 +1142,11 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
|
||||
uint64 rows;
|
||||
BufferUsage bufusage_start,
|
||||
bufusage;
|
||||
WalUsage walusage_start,
|
||||
walusage;
|
||||
|
||||
bufusage_start = pgBufferUsage;
|
||||
walusage_start = pgWalUsage;
|
||||
INSTR_TIME_SET_CURRENT(start);
|
||||
|
||||
exec_nested_level++;
|
||||
@ -1154,6 +1176,10 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
|
||||
memset(&bufusage, 0, sizeof(BufferUsage));
|
||||
BufferUsageAccumDiff(&bufusage, &pgBufferUsage, &bufusage_start);
|
||||
|
||||
/* calc differences of WAL counters. */
|
||||
memset(&walusage, 0, sizeof(WalUsage));
|
||||
WalUsageAccumDiff(&walusage, &pgWalUsage, &walusage_start);
|
||||
|
||||
pgss_store(queryString,
|
||||
0, /* signal that it's a utility stmt */
|
||||
pstmt->stmt_location,
|
||||
@ -1162,6 +1188,7 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
|
||||
INSTR_TIME_GET_MILLISEC(duration),
|
||||
rows,
|
||||
&bufusage,
|
||||
&walusage,
|
||||
NULL);
|
||||
}
|
||||
else
|
||||
@ -1197,7 +1224,8 @@ pgss_hash_string(const char *str, int len)
|
||||
*
|
||||
* If jstate is not NULL then we're trying to create an entry for which
|
||||
* we have no statistics as yet; we just want to record the normalized
|
||||
* query string. total_time, rows, bufusage are ignored in this case.
|
||||
* query string. total_time, rows, bufusage and walusage are ignored in this
|
||||
* case.
|
||||
*
|
||||
* If kind is PGSS_PLAN or PGSS_EXEC, its value is used as the array position
|
||||
* for the arrays in the Counters field.
|
||||
@ -1208,6 +1236,7 @@ pgss_store(const char *query, uint64 queryId,
|
||||
pgssStoreKind kind,
|
||||
double total_time, uint64 rows,
|
||||
const BufferUsage *bufusage,
|
||||
const WalUsage *walusage,
|
||||
pgssJumbleState *jstate)
|
||||
{
|
||||
pgssHashKey key;
|
||||
@ -1402,6 +1431,9 @@ pgss_store(const char *query, uint64 queryId,
|
||||
e->counters.blk_read_time += INSTR_TIME_GET_MILLISEC(bufusage->blk_read_time);
|
||||
e->counters.blk_write_time += INSTR_TIME_GET_MILLISEC(bufusage->blk_write_time);
|
||||
e->counters.usage += USAGE_EXEC(total_time);
|
||||
e->counters.wal_records += walusage->wal_records;
|
||||
e->counters.wal_num_fpw += walusage->wal_num_fpw;
|
||||
e->counters.wal_bytes += walusage->wal_bytes;
|
||||
|
||||
SpinLockRelease(&e->mutex);
|
||||
}
|
||||
@ -1449,8 +1481,8 @@ pg_stat_statements_reset(PG_FUNCTION_ARGS)
|
||||
#define PG_STAT_STATEMENTS_COLS_V1_1 18
|
||||
#define PG_STAT_STATEMENTS_COLS_V1_2 19
|
||||
#define PG_STAT_STATEMENTS_COLS_V1_3 23
|
||||
#define PG_STAT_STATEMENTS_COLS_V1_8 29
|
||||
#define PG_STAT_STATEMENTS_COLS 29 /* maximum of above */
|
||||
#define PG_STAT_STATEMENTS_COLS_V1_8 32
|
||||
#define PG_STAT_STATEMENTS_COLS 32 /* maximum of above */
|
||||
|
||||
/*
|
||||
* Retrieve statement statistics.
|
||||
@ -1786,6 +1818,23 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo,
|
||||
values[i++] = Float8GetDatumFast(tmp.blk_read_time);
|
||||
values[i++] = Float8GetDatumFast(tmp.blk_write_time);
|
||||
}
|
||||
if (api_version >= PGSS_V1_8)
|
||||
{
|
||||
char buf[256];
|
||||
Datum wal_bytes;
|
||||
|
||||
values[i++] = Int64GetDatumFast(tmp.wal_records);
|
||||
values[i++] = Int64GetDatumFast(tmp.wal_num_fpw);
|
||||
|
||||
snprintf(buf, sizeof buf, UINT64_FORMAT, tmp.wal_bytes);
|
||||
|
||||
/* Convert to numeric. */
|
||||
wal_bytes = DirectFunctionCall3(numeric_in,
|
||||
CStringGetDatum(buf),
|
||||
ObjectIdGetDatum(0),
|
||||
Int32GetDatum(-1));
|
||||
values[i++] = wal_bytes;
|
||||
}
|
||||
|
||||
Assert(i == (api_version == PGSS_V1_0 ? PG_STAT_STATEMENTS_COLS_V1_0 :
|
||||
api_version == PGSS_V1_1 ? PG_STAT_STATEMENTS_COLS_V1_1 :
|
||||
|
@ -101,6 +101,29 @@ SELECT * FROM test WHERE a IN (1, 2, 3, 4, 5);
|
||||
|
||||
SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
|
||||
|
||||
--
|
||||
-- INSERT, UPDATE, DELETE on test table to validate WAL generation metrics
|
||||
--
|
||||
SELECT pg_stat_statements_reset();
|
||||
|
||||
-- utility "create table" should not be shown
|
||||
CREATE TABLE pgss_test (a int, b char(20));
|
||||
|
||||
INSERT INTO pgss_test VALUES(generate_series(1, 10), 'aaa');
|
||||
UPDATE pgss_test SET b = 'bbb' WHERE a > 7;
|
||||
DELETE FROM pgss_test WHERE a > 9;
|
||||
-- DROP test table
|
||||
SET pg_stat_statements.track_utility = TRUE;
|
||||
DROP TABLE pgss_test;
|
||||
SET pg_stat_statements.track_utility = FALSE;
|
||||
|
||||
-- Check WAL is generated for the above statements
|
||||
SELECT query, calls, rows,
|
||||
wal_bytes > 0 as wal_bytes_generated,
|
||||
wal_records > 0 as wal_records_generated,
|
||||
wal_records = rows as wal_records_as_rows
|
||||
FROM pg_stat_statements ORDER BY query COLLATE "C";
|
||||
|
||||
--
|
||||
-- pg_stat_statements.track = none
|
||||
--
|
||||
|
@ -264,6 +264,33 @@
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><structfield>wal_bytes</structfield></entry>
|
||||
<entry><type>numeric</type></entry>
|
||||
<entry></entry>
|
||||
<entry>
|
||||
Total amount of WAL bytes generated by the statement
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><structfield>wal_records</structfield></entry>
|
||||
<entry><type>bigint</type></entry>
|
||||
<entry></entry>
|
||||
<entry>
|
||||
Total count of WAL records generated by the statement
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><structfield>wal_num_fpw</structfield></entry>
|
||||
<entry><type>bigint</type></entry>
|
||||
<entry></entry>
|
||||
<entry>
|
||||
Total count of WAL full page writes generated by the statement
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
Loading…
Reference in New Issue
Block a user