diff --git a/doc/src/sgml/pgstatstatements.sgml b/doc/src/sgml/pgstatstatements.sgml new file mode 100644 index ca7bd44..2355f1a *** a/doc/src/sgml/pgstatstatements.sgml --- b/doc/src/sgml/pgstatstatements.sgml *************** *** 24,33 **** The statistics gathered by the module are made available via a system view ! named pg_stat_statements. This view contains one row for ! each distinct query text, database ID, and user ID (up to the maximum ! number of distinct statements that the module can track). The columns ! of the view are shown in . --- 24,78 ---- The statistics gathered by the module are made available via a system view ! named pg_stat_statements. The module normalizes queries, ! matching them based on an internal hash value. ! pg_stat_statements contains one row for each distinct ! combination of internal query hash, database ID, and user ID (up to the ! maximum number of distinct statements that the module can track). The ! columns of the view are shown in ! . ! ! ! ! Utility commands are all those other than SELECT, ! INSERT, UPDATE and DELETE. In the case ! of utility statements, the query hash value identifier is derived from the ! query string. In the case of all other statements, the statement's query ! tree is hashed to produce its query hash identifier. The query tree is an ! internal structure that results from the transformation process, later in the ! parser stage, immediately prior to the rewrite stage. Queries that are ! deemed to be equivalent, due to not actually differing in ways that the ! implementation deems essential to the query, have execution statistics ! aggregated into a single entry. This is particularly useful for queries with ! inline parameters. ! ! ! ! Matching queries based on their query tree hash value can produce results ! that are not consistent with an implementation that differentiates based on ! each query's SQL string, in non-obvious ways. For example, the current value ! of search_path might affect query differentiation if a change ! caused parse analysis to resolve different relations at different times, such ! as relations that have identical definitions but are located in different ! schemas. The two resulting distinct entries would have identical query ! strings. ! ! ! ! The execution costs of DO INSTEAD and DO ALSO rules ! are attributed to their originating query; a separate entry will not be ! created for the rule action. DO NOTHING rules will naturally not ! add an entry at all, since a query is not actually executed. ! ! ! ! pg_stat_statements considers some utility commands to ! consist of two distinct commands: The utility command proper, and a nested ! DML command. Such utility commands include DECLARE ! CURSOR, SELECT INTO and EXPLAIN ANALYZE. ! Therefore, to see the true execution costs of these statements, it is ! necessary to set both pg_stat_statements.track_utility to 'on' and ! pg_stat_statements.track to 'all'.
*************** *** 61,67 **** querytext ! Text of the statement (up to bytes) --- 106,112 ---- query text ! Representative, canonicalized text of the statement (up to bytes) *************** *** 193,206 **** queries executed by other users. They can see the statistics, however, if the view has been installed in their database. ! ! Note that statements are considered the same if they have the same text, ! regardless of the values of any out-of-line parameters used in the ! statement. Using out-of-line parameters will help to group statements ! together and may make the statistics more useful. ! ! Functions --- 238,256 ---- queries executed by other users. They can see the statistics, however, if the view has been installed in their database. + + + A notable artefact of the module's query hash matching based implementation + is that there may be undetectable collisions. While such collisions are very + unlikely, the possibility cannot be absolutely precluded, and as such the + count values of two distinct queries may be incorrectly aggregated together + as a single entry within pg_stat_statements in isolated + cases. However, it is guaranteed that such collisions cannot occur between + entries for different databases or different users. + + ! Functions *************** *** 254,264 **** pg_stat_statements.track controls which statements are counted by the module. ! Specify top to track top-level statements (those issued ! directly by clients), all to also track nested statements ! (such as statements invoked within functions), or none to ! disable. ! The default value is top. Only superusers can change this setting. --- 304,314 ---- pg_stat_statements.track controls which statements are counted by the module. ! Specify top to track top-level statements (those issued ! directly by clients), all to also track nested statements ! (such as statements invoked within functions), or none to ! disable. ! The default value is top. Only superusers can change this setting. *************** *** 271,282 **** ! pg_stat_statements.track_utility controls whether ! utility commands are tracked by the module. Utility commands are ! all those other than SELECT, INSERT, ! UPDATE and DELETE. ! The default value is on. ! Only superusers can change this setting. --- 321,329 ---- ! pg_stat_statements.track_utility controls whether ! utility commands are tracked by the module. The default value is ! on. Only superusers can change this setting. *************** pg_stat_statements.track = all *** 329,348 **** bench=# SELECT pg_stat_statements_reset(); $ pgbench -i bench ! $ pgbench -c10 -t300 -M prepared bench bench=# \x bench=# SELECT query, calls, total_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_time DESC LIMIT 5; -[ RECORD 1 ]--------------------------------------------------------------------- ! query | UPDATE pgbench_branches SET bbalance = bbalance + $1 WHERE bid = $2; calls | 3000 total_time | 9.60900100000002 rows | 2836 hit_percent | 99.9778970000200936 -[ RECORD 2 ]--------------------------------------------------------------------- ! query | UPDATE pgbench_tellers SET tbalance = tbalance + $1 WHERE tid = $2; calls | 3000 total_time | 8.015156 rows | 2990 --- 376,395 ---- bench=# SELECT pg_stat_statements_reset(); $ pgbench -i bench ! $ pgbench -c10 -t300 bench=# \x bench=# SELECT query, calls, total_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_time DESC LIMIT 5; -[ RECORD 1 ]--------------------------------------------------------------------- ! query | UPDATE pgbench_branches SET bbalance = bbalance + ? WHERE bid = ?; calls | 3000 total_time | 9.60900100000002 rows | 2836 hit_percent | 99.9778970000200936 -[ RECORD 2 ]--------------------------------------------------------------------- ! query | UPDATE pgbench_tellers SET tbalance = tbalance + ? WHERE tid = ?; calls | 3000 total_time | 8.015156 rows | 2990 *************** total_time | 0.310624 *** 354,360 **** rows | 100000 hit_percent | 0.30395136778115501520 -[ RECORD 4 ]--------------------------------------------------------------------- ! query | UPDATE pgbench_accounts SET abalance = abalance + $1 WHERE aid = $2; calls | 3000 total_time | 0.271741999999997 rows | 3000 --- 401,407 ---- rows | 100000 hit_percent | 0.30395136778115501520 -[ RECORD 4 ]--------------------------------------------------------------------- ! query | UPDATE pgbench_accounts SET abalance = abalance + ? WHERE aid = ?; calls | 3000 total_time | 0.271741999999997 rows | 3000