postgres extension pg_stat_statement - ghdrako/doc_snipets GitHub Wiki
-
https://www.timescale.com/blog/identify-postgresql-performance-bottlenecks-with-pg_stat_statements/
-
https://docs.yugabyte.com/preview/explore/query-1-performance/pg-stat-statements/
-
It's part of contrib module but not enable by default.
- Must be loaded by
shared_preload_libraries
inpostgres.conf
- Must be loaded by
-
Tracks aggregated statistics of all queries in the cluster
pg_stat_statements is useed for monitoring your queries, and extract information for the historically best to worst performing queries, allowing you to know what queries should be optimized first. This extension can also be used in conjunction with load tests, allowing you to pinpoint queries that contribute to potential bottlenecks in your application.
pg_stat_statements is included in the contrib module, so it ships with standard Postgres, but might not be automatically enabled:
- If you're using a managed Postgres system such as Crunchy Bridge, pg_stat_statements may have already been added in postgresql.conf. (Tip: run
SHOW shared_preload_libraries
; to check.) In that case you can skip to the next step. - Log back in to Postgres. In the database which you want to access pg_stat_statements, run:
CREATE EXTENSION pg_stat_statements;
Setting up pg_stat_statements
Options offered by the extension to customize how it behaves.
-
pg_stat_statements.max
โ sets the max number of statements PostgreSQL will keep track of.hink of this as rows in the pg_stat_statements table. The Default is 5000. -
pg_stat_statements.track
โ Default is top.- all โ Tracks all statements, including those inside function calls
- top โ Tracks only statements issued by clients
- none โ disable collection
-
pg_stat_statements.track_utility
โ On or Off . Tracks whether or not queries besides just SELECT, UPDATE, DELETE AND INSERT queries are tracked. Default is on. -
pg_stat_statements.save
โ On or Off. This sets whether the data should reset when the instance restarts, setting to off will reset the * pg_stat_statements table after instance restart.
$ cat postgresql.conf
pg_stat_statements.max = 10000
pg_stat_statements.track = all
track_activity_query_size = 2048
shared_preload_libraries = 'pg_stat_statements'
In Google Cloud SQL, this step above is not required as it is already supported.
Add extension
CREATE EXTENSION IF NOT EXISTS "pg_stat_statements";
If you run on a major cloud provider there is a strong likelihood they have already installed and enabled it for you.
Drop extension
drop extension pg_stat_statements;
Reset stats:
SELECT pg_stat_reset(); -- Local database
SELECT pg_stat_statements_reset(); -- For Google Cloud SQL
Useful after a significant optimization effort to see if the new query performs better.
Identify Inefficient Queries through Monitoring
SELECT
query,
calls,
total_exec_time,
rows,
100.0 * shared_blks_hit / nullif(shared_blks_hit + shared_blks_read, 0) AS hit_percent
FROM
pg_stat_statements
ORDER BY
total_exec_time DESC
LIMIT
5;
This SQL command allows identifying the most critical queries for performance and thus represents a valuable first step in the optimization of the database.
Usage
Once pg_stat_statements is installed, it begins silently going to work under the covers. Pg_stat_statements records queries that are run against your database, strips out a number of variables from them, and then saves data about the query, such as how long it took, as well as what happened to underlying reads/writes.
Note: It doesnโt save each individual query, rather it parameterizes them and then saves the aggregated result
PGSS performs a normalization process for each query, removing specific parameters and replacing their values with placeholder characters (question marks). The normalized query gets a query identifier (queryid), which represents a query group. Similar normalized queries placed into the same group are grouped together. Statistics are collected at the group level. PGSS presents the statistics in a catalog view that you can enable access to for your database.
More than 40 fields of information are collected as statistics[164] for PGSS. Some of the information includes the number of calls for queries within that group and their execution time min, max, mean, and standard deviation. These statistics are cumulative, growing until less-used query groups are evicted or statistics are reset. Rows and blocks that are accessed are included in the stats, which can be used to help identify excessive IO.
As queries are received in PostgreSQL, PGSS places them into groups, gives the group an identifier, and captures group-level statistics. PGSS tracks 5000 normalized queries (or query groups) by default, which can be increased by setting pg_stat_statements.max. The least-executed queries are discarded when the max is reached. To reset the statistics, run SELECT rideshare.PG_STAT_STATEMENTS_RESET(); from psql. Great. If you reset the statistics, run the simulation again. Once youโve done that, you should now have some stats to work with.
View pg_stat_statements
\d pg_stat_statements
SELECT * FROM pg_stat_statements;
SELECT
(total_exec_time / 1000 / 60) as total_min,
mean_exec_time as avg_ms,
calls,
query
FROM pg_stat_statements
ORDER BY 1 DESC
LIMIT 500;
columns that will be the most useful for spotting potential problems with your queries.
- calls: the number of times this query has been called.
- total_exec_time: the total time spent executing the query, in milliseconds.
- rows: the total number of rows retrieved by this query.
- shared_blks_hit: the number of blocks already cached when read for the query.
- shared_blks_read: the number of blocks that had to be read from the disk to satisfy all calls for this query form.
Three quick reminders about the data columns above:
- All values are cumulative since the last time the service was started, or a superuser manually resets the values.
- All values are for the same query form after parameterizing the query and based on the resulting hashed queryid.
- The current configuration for Timescale Cloud services does not track query planning statistics because of the small added overhead. We may allow this through user configuration in the future.
Top 10 I/O-intensive queries
select userid::regrole, dbid, query
from pg_stat_statements
order by (blk_read_time+blk_write_time)/calls desc
limit 10;
Top 10 time-consuming queries
select userid::regrole, dbid, query
from pg_stat_statements
order by mean_time desc
limit 10;
SELECT round((100 * total_exec_time / sum(total_exec_time)
OVER ())::numeric, 2) percent,
round(total_exec_time::numeric, 2) AS total,
calls,
round(mean_exec_time::numeric, 2) AS mean,
substring(query, 1, 200)
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 10;
Top 10 response-time outliers
select userid::regrole, dbid, query
from pg_stat_statements
order by stddev_time desc
limit 10;
Top 10 queries by memory usage
select userid::regrole, dbid, query
from pg_stat_statements
order by (shared_blks_hit+shared_blks_dirtied) desc
limit 10;
Top 10 consumers of temporary space
select userid::regrole, dbid, query
from pg_stat_statements
order by temp_blks_written desc
limit 10;
Top 100 very frequently queries run, as well as what they consume on average:
SELECT
(total_time / 1000 / 60) as total,
(total_time/calls) as avg,
query
FROM pg_stat_statements
ORDER BY 1 DESC
LIMIT 100;
Long-Running Queries
SELECT calls,
mean_exec_time,
query
FROM pg_stat_statements
WHERE calls > 500
AND shared_blks_hit > 0
ORDER BY mean_exec_time DESC
LIMIT 10;
Hit Cache Ratio
SELECT calls,
shared_blks_hit,
shared_blks_read,
shared_blks_hit/(shared_blks_hit+shared_blks_read)::NUMERIC*100 hit_cache_ratio,
query
FROM pg_stat_statements
WHERE calls > 500
AND shared_blks_hit > 0
ORDER BY calls DESC, hit_cache_ratio ASC
LIMIT 10;
Queries With High Standard Deviation
SELECT calls,
min_exec_time,
max_exec_time,
mean_exec_time,
stddev_exec_time,
(stddev_exec_time/mean_exec_time) AS coeff_of_variance,
query
FROM statements
WHERE calls > 500
AND shared_blks_hit > 0
ORDER BY mean_exec_time DESC
LIMIT 10;
Note on I/O stats
A tip from my colleague Greg Smith: if you want to use the block read and write time (blk_read_time and blk_write_time) statistics, you also need to turn on the track_io_timing parameter in postgresql.conf. That's recommended if you want all the features pg_stat_statements can deliver. It's disabled by default because timing things is very slow on some systems.
To check how fast the timers in your system are, use the pg_test_timing utility. The overhead of collecting all this timing data is low for most hardware.
I hadn't enabled track_io_timing, so we've focused on more simple examples for now. Do keep an eye out for a future deep dive into this topic on our blog.
Logs
query texts are "kept in an external disk file, and do not consume shared memory" (taken from the official docs). pgstat_statements should leave only a relatively small footprint on your system especially compared to logging _all of the things. That said, you could also make sure to set a lower threshold on pg_stat_statements.max, or set only certain types of statements to be tracked using the pg_stat_statements.track parameters.