Redrock Postgres 搜索 英文
版本: 9.3 / 9.4 / 9.5 / 9.6 / 10 / 11 / 12 / 13 / 14 / 15 / 16 / 17

F.30. pg_stat_statements — 跟踪 SQL 规划和执行的统计数据 #

F.30.1. pg_stat_statements 视图
F.30.2. pg_stat_statements_info 视图
F.30.3. 函数
F.30.4. 配置参数
F.30.5. 输出样本
F.30.6. 作者

pg_stat_statements 模块提供了一种跟踪服务器执行的所有 SQL 语句的规划和执行的统计数据的方法。

必须通过将 pg_stat_statements 添加到 postgresql.conf 中的 shared_preload_libraries 来加载该模块,因为它需要额外的共享内存。这意味着需要重新启动服务器才能添加或删除该模块。此外,必须启用查询标识符计算才能激活该模块,如果将 compute_query_id 设置为 autoon,或者加载计算查询标识符的任何第三方的模块,该操作会自动进行。

pg_stat_statements 处于活动状态时,它会跨服务器的所有数据库跟踪统计数据。为了访问和处理这些统计数据,该模块提供视图 pg_stat_statementspg_stat_statements_info,以及实用函数 pg_stat_statements_resetpg_stat_statements。这些函数不在全局范围内可用,但是可以通过 CREATE EXTENSION pg_stat_statements 为特定数据库启用。

F.30.1.  视图 pg_stat_statements #

该模块收集的统计数据通过名为 pg_stat_statements 的视图提供。该视图针对数据库 ID、用户 ID、查询 ID 的每个不重复组合包含一行,以及它是否是顶级语句(最多达到该模块可以跟踪的不重复语句数)。视图的列显示在 表 F.21 中。

表 F.21. pg_stat_statements

列类型

说明

userid oid(引用 pg_authid.oid

执行该语句的用户的 OID

dbid oid(关联pg_database.oid

执行语句所在的数据库的 OID

toplevel bool

如果查询作为顶级语句执行,则为 True(如果 pg_stat_statements.track 设置为 top,则始终为 True)

queryid bigint

哈希代码用于识别完全相同的标准化查询。

query text

代表性语句的文本

plans bigint

对语句进行规划的次数(如果已启用 pg_stat_statements.track_planning,否则为零)

total_plan_time double precision

规划语句的总时间(如果已启用 pg_stat_statements.track_planning,否则为零),单位为毫秒

min_plan_time double precision

规划语句的最少时间,单位为毫秒。如果已禁用 pg_stat_statements.track_planning,或者使用 pg_stat_statements_reset 函数将计数器重置为 minmax_only 参数设置为 true,以后不再规划,该字段将为零。

max_plan_time double precision

规划语句的最长时间,单位为毫秒。如果已禁用 pg_stat_statements.track_planning,或者使用 pg_stat_statements_reset 函数将计数器重置为 minmax_only 参数设置为 true,以后不再规划,该字段将为零。

mean_plan_time double precision

规划语句的平均时间,单位为毫秒(如果已启用 pg_stat_statements.track_planning,否则为零)

stddev_plan_time double precision

规划语句的时间总体标准差,单位为毫秒(如果已启用 pg_stat_statements.track_planning,否则为零)

calls bigint

执行语句的次数

total_exec_time double precision

执行语句的总时间,单位为毫秒

min_exec_time double precision

执行语句的最小时间,单位为毫秒,此字段在使用 minmax_only 参数设置为 truepg_stat_statements_reset 函数执行重置后,在首次执行语句之前一直为零

max_exec_time double precision

执行语句所花费的最大时间,单位为毫秒。如果在使用 pg_stat_statements_reset 函数执行复位(将 minmax_only 参数设为 true)之后未执行该语句,则该字段将为零。

mean_exec_time double precision

执行该语句平均花费的时间,单位为毫秒。

stddev_exec_time double precision

执行该语句所花费时间的总体标准偏差,单位为毫秒。

rows bigint

该语句检索或影响的行总数

shared_blks_hit bigint

该语句的共享块高速缓存命中总数。

shared_blks_read bigint

该语句读取的共享块总数。

shared_blks_dirtied bigint

该语句弄脏的共享块总数。

shared_blks_written bigint

该语句写入的共享块总数。

local_blks_hit bigint

该语句的本地块高速缓存命中总数。

local_blks_read bigint

该语句读取的本地块总数。

local_blks_dirtied bigint

该语句弄脏的本地块总数。

local_blks_written bigint

该语句写入的本地块总数。

temp_blks_read bigint

该语句读取的 temp 块总数。

temp_blks_written bigint

该语句写入的 temp 块总数。

shared_blk_read_time double precision

该语句花在读取共享块上的总时间(如果启用了 track_io_timing,则单位为毫秒,否则为 0)

shared_blk_write_time double precision

该语句花在写入共享块上的总时间(如果启用了 track_io_timing,则单位为毫秒,否则为 0)

local_blk_read_time double precision

该语句花在读取本地块上的总时间(如果启用了 track_io_timing,则单位为毫秒,否则为 0)

local_blk_write_time double precision

该语句花在写入本地块上的总时间(如果启用了 track_io_timing,则单位为毫秒,否则为 0)

temp_blk_read_time double precision

该语句花在读取临时文件块上的总时间(如果启用了 track_io_timing,则单位为毫秒,否则为 0)

temp_blk_write_time double precision

该语句用于写入临时文件块的总时间,单位为毫秒(如果启用了 track_io_timing,否则为零)

wal_records bigint

该语句生成的 WAL 记录总数

wal_fpi bigint

该语句生成的 WAL 整页映像总数

wal_bytes numeric

该语句生成的 WAL 总量,单位为字节

jit_functions bigint

该语句 JIT 编译的函数总数

jit_generation_time double precision

该语句用于生成 JIT 代码所花费的总时间,单位为毫秒

jit_inlining_count bigint

内联函数的次数

jit_inlining_time double precision

该语句用于内联函数所花费的总时间,单位为毫秒

jit_optimization_count bigint

该语句进行优化的次数

jit_optimization_time double precision

该语句用于优化所花费的总时间,单位为毫秒

jit_emission_count bigint

已生成代码的次数

jit_emission_time double precision

该语句用于生成代码所花费的总时间,单位为毫秒

jit_deform_count bigint

该语句 JIT 编译的元组变形函数总数

jit_deform_time double precision

该语句用于 JIT 编译元组变形函数所花费的总时间,单位为毫秒

stats_since timestamp with time zone

该语句开始收集统计信息的时间

minmax_stats_since timestamp with time zone

该语句开始收集最小/最大统计信息的时间(字段 min_plan_timemax_plan_timemin_exec_timemax_exec_time


出于安全原因,只有超级用户和具有 pg_read_all_stats 角色特权的角色才能查看其他用户执行的查询的 SQL 文本和 queryid。不过,如果该视图已安装在用户的数据库中,其他用户可以看到统计信息。

可计划查询(即 SELECTINSERTUPDATEDELETEMERGE)以及实用程序命令合并到一个 pg_stat_statements 条目中,只要根据内部散列计算,它们具有相同的查询结构。通常,如果除查询中出现的文本常量的值之外,这两种查询在语义上是等价的,就认为这两条查询是相同的。

说明

以下有关常量替换和 queryid 的详细信息仅当 compute_query_id 启用后才适用。如果您使用外部模块而不是计算 queryid,您应该参考其文档以获取详细信息。

当常数的值被忽略以将查询与其他查询进行匹配时,常数将替换为参数符号,例如 $1,在 pg_stat_statements 显示中。其余的查询文本是第一个具有与 pg_stat_statements 条目关联的特定 queryid 哈希值查询的文本。

可以在 pg_stat_statements 观察到对可应用规范化的查询具有常量值,特别是在条目释放率很高的情况下。为了降低这种情况发生的可能性,请考虑增加 pg_stat_statements.max。在 30.2 节 讨论的 pg_stat_statements_info 视图提供有关条目释放的统计信息。

在某些情况下,文本明显不同的查询可能会合并到一个 pg_stat_statements 条目中。通常这只会发生在语义等价查询中,但散列冲突可能会导致不相关的查询合并到一个条目中,但这种情况很小。(然而,这不会发生对于属于不同用户或数据库的查询。)

由于 queryid 哈希值是在查询的后解析分析表示上计算的,因此反之亦成立:具有相同文本的查询可能会显示为单独的条目,如果它们因不同 search_path 设置等因素导致语义不同。

pg_stat_statements 消费者可能会希望将 queryid(或许与 dbiduserid 结合使用)用作每个条目的更稳定且可靠的标识符,而不是其查询文本。但了解 queryid 哈希值稳定性只有有限保证这一点非常重要。由于标识符是从后解析分析树派生的,因此它的值是后解析分析树中的内部对象标识符等因素的函数。这有一些违反直觉的含义。例如,如果 pg_stat_statements 引用两条明显相同的查询并在两次查询执行之间删除再重建了该表,那么 pg_stat_statements 将认为这些查询各不相同。哈希流程还对机器架构及平台的其他方面差异很敏感。此外,我们不能安全地假设 queryidPostgreSQL 的主要版本之间都是稳定的。

我们预计基于物理 WAL 重放参与复制的两台服务器对同一查询具有相同的 queryid 值。然而,逻辑复制方案并不会保证保留副本在所有相关详细信息上的相同性,因此 queryid 不会成为用来累积多组逻辑副本成本的有用标识符。如有疑问,建议直接测试。

通常,我们可以假设 queryid 值在 PostgreSQL 的次要版本发布之间保持稳定,前提是实例在同一机器架构上运行且编录元数据详细信息匹配。只有在万不得已的情况下,次要版本之间才会中断兼容性。

用于替换原始查询文本中的常数的参数符号开始于原始查询文本中最高 $n 参数的下一个数字,或在没有该参数时从 $1 开始。值得注意的是,在某些情况下可能存在影响该编号的隐藏参数符号。例如,PL/pgSQL 使用隐藏参数符号将函数局部变量值插入到查询中,因此类似 SELECT i + 1 INTO jPL/pgSQL 语句的代表文本类似 SELECT i + $2

代表性查询文本保存在外部磁盘文件中,不占用共享内存。因此,即使查询文本非常长,也可以成功存储。但如果积累了很多长的查询文本,外部文件可能会增长得难以管理。如果发生这种情况,pg_stat_statements 会选择丢弃查询文本作为一种恢复方法,随后 pg_stat_statements 视图中的所有现有条目将显示空 query 字段,尽管与每个 queryid 关联的统计信息得以保留。如果发生这种情况,请考虑减少 pg_stat_statements.max 以防止再次发生。

structfieldcalls 并不总是一致,因为规划和执行统计数据在各自的结束阶段更新,并且仅针对成功操作更新。例如,如果语句在计划阶段成功但在执行阶段失败,则只有其计划统计数据将被更新。如果规划被跳过,因为使用了缓存计划,则只有其执行统计数据将被更新。

F.30.2.  pg_stat_statements_info 视图 #

pg_stat_statements 模块的统计数据本身得到跟踪,并通过名为 pg_stat_statements_info 的视图提供。此视图仅包含一行。该视图的列显示在 表 F.22 中。

表 F.22. pg_stat_statements_info

列类型

说明

dealloc bigint

由于观察到的语句比 pg_stat_statements.max 多,因此 pg_stat_statements 条目中关于执行最少的语句的总释放次数

stats_reset 带时区的 timestamp

pg_stat_statements 视图中所有统计数据上次重置的时间。


F.30.3. 函数 #

pg_stat_statements_reset(userid Oid, dbid Oid, queryid bigint, minmax_only boolean) 返回带时区的 timestamp

pg_stat_statements_reset 丢弃当前 pg_stat_statements 收集的、对应于已指定 useriddbidqueryid 的统计信息。如果任何参数没有指定,则使用默认值 0(无效)代替它们,而使用其他参数匹配的统计信息将会被重置。如果未指定任何参数或所有指定的参数都是 0(无效),则它将会丢弃所有统计信息。如果 pg_stat_statements 视图中的所有统计信息都被丢弃,它还将重置 pg_stat_statements_info 视图中的统计信息。当 minmax_onlytrue 时,只有最小和最大规划和执行时间的数值会被重置(即 min_plan_timemax_plan_timemin_exec_timemax_exec_time 字段)。minmax_only 参数的默认值为 false。上次执行最小值/最大值重置的时间显示在 pg_stat_statements 视图的 minmax_stats_since 字段中。此功能返回重置时间。此时间会保存到 pg_stat_statements_info 视图的 stats_reset 字段或 pg_stat_statements 视图的 minmax_stats_since 字段(如果实际执行了相应的重置)。默认情况下,此功能只能由超级用户执行。可以通过 GRANT 向其他人授予访问权限。

pg_stat_statements(showtext boolean) returns setof record

定义 pg_stat_statements 视图的方式是使用一个函数,该函数也称为 pg_stat_statements。客户端可以调用 pg_stat_statements,并通过指定 showtext := false 忽略查询文本(也就是说,与视图的 query 列相对应的 OUT 参数将返回 null)。此功能旨在为可能希望避免重复检索长度不确定的查询文本的外部工具提供支持。此类工具可以自行缓存每个条目观察到的第一个查询文本,因为这就是 pg_stat_statements 本身所做的,然后再根据需要检索查询文本。由于服务器将查询文本存储在一个文件中,因此此方法可以减少重复检查 pg_stat_statements 数据时的物理 I/O。

F.30.4. 配置参数 #

pg_stat_statements.max (integer)

pg_stat_statements.max 是该模块跟踪的最大语句数(即 pg_stat_statements 视图中的最大行数)。如果观察到不同的语句比该语句数多,那么关于执行次数最少的语句的信息将被丢弃。可以在 pg_stat_statements_info 视图中看到该信息被丢弃的次数。默认值为 5000。此参数只能在服务器启动时设置。

pg_stat_statements.track (enum)

pg_stat_statements.track 控制该模块要计数哪些语句。指定 top 跟踪顶级语句(客户端直接发出的语句)、all 还跟踪嵌套语句(比如函数中调用的语句)或者 none 禁用语句统计收集。默认值为 top。只有超级用户可以更改此设置。

pg_stat_statements.track_utility (boolean)

pg_stat_statements.track_utility 控制该模块是否跟踪实用程序命令。实用程序命令是除 SELECTINSERTUPDATEDELETEMERGE 以外的所有命令。默认值为 on。只有超级用户可以更改此设置。

pg_stat_statements.track_planning (boolean)

pg_stat_statements.track_planning 控制该模块是否跟踪规划操作和持续时间。在具有相同查询结构的语句由多个并行连接同时执行来竞争更新少量 pg_stat_statements 条目时,启用此参数可能会造成显著的性能损失。默认值为 off。只有超级用户可以更改此设置。

pg_stat_statements.save (boolean)

pg_stat_statements.save 指定是否存储跨服务器关闭的语句统计。如果为 off,则统计信息不会在关闭时保存,也不会在服务器启动时重新加载。默认值为 on。此参数只能在 postgresql.conf 文件中或服务器命令行中设置。

该模块相对于 pg_stat_statements.max 需要额外的共享内存。请注意,只要加载模块就会消耗该内存,即使将 pg_stat_statements.track 设置为 none

这些参数必须在 postgresql.conf 中设置。典型用法可能为

# postgresql.conf
shared_preload_libraries = 'pg_stat_statements'

compute_query_id = on
pg_stat_statements.max = 10000
pg_stat_statements.track = all

F.30.5. 示例输出 #

bench=# SELECT pg_stat_statements_reset();

$ pgbench -i bench
$ pgbench -c10 -t300 bench

bench=# \x
bench=# 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;
-[ RECORD 1 ]---+--------------------------------------------------​------------------
query           | UPDATE pgbench_branches SET bbalance = bbalance + $1 WHERE bid = $2
calls           | 3000
total_exec_time | 25565.855387
rows            | 3000
hit_percent     | 100.0000000000000000
-[ RECORD 2 ]---+--------------------------------------------------​------------------
query           | UPDATE pgbench_tellers SET tbalance = tbalance + $1 WHERE tid = $2
calls           | 3000
total_exec_time | 20756.669379
rows            | 3000
hit_percent     | 100.0000000000000000
-[ RECORD 3 ]---+--------------------------------------------------​------------------
query           | copy pgbench_accounts from stdin
calls           | 1
total_exec_time | 291.865911
rows            | 100000
hit_percent     | 100.0000000000000000
-[ RECORD 4 ]---+--------------------------------------------------​------------------
query           | UPDATE pgbench_accounts SET abalance = abalance + $1 WHERE aid = $2
calls           | 3000
total_exec_time | 271.232977
rows            | 3000
hit_percent     | 98.8454011741682975
-[ RECORD 5 ]---+--------------------------------------------------​------------------
query           | alter table pgbench_accounts add primary key (aid)
calls           | 1
total_exec_time | 160.588563
rows            | 0
hit_percent     | 100.0000000000000000


bench=# SELECT pg_stat_statements_reset(0,0,s.queryid) FROM pg_stat_statements AS s
            WHERE s.query = 'UPDATE pgbench_branches SET bbalance = bbalance + $1 WHERE bid = $2';

bench=# 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;
-[ RECORD 1 ]---+--------------------------------------------------​------------------
query           | UPDATE pgbench_tellers SET tbalance = tbalance + $1 WHERE tid = $2
calls           | 3000
total_exec_time | 20756.669379
rows            | 3000
hit_percent     | 100.0000000000000000
-[ RECORD 2 ]---+--------------------------------------------------​------------------
query           | copy pgbench_accounts from stdin
calls           | 1
total_exec_time | 291.865911
rows            | 100000
hit_percent     | 100.0000000000000000
-[ RECORD 3 ]---+--------------------------------------------------​------------------
query           | UPDATE pgbench_accounts SET abalance = abalance + $1 WHERE aid = $2
calls           | 3000
total_exec_time | 271.232977
rows            | 3000
hit_percent     | 98.8454011741682975
-[ RECORD 4 ]---+--------------------------------------------------​------------------
query           | alter table pgbench_accounts add primary key (aid)
calls           | 1
total_exec_time | 160.588563
rows            | 0
hit_percent     | 100.0000000000000000
-[ RECORD 5 ]---+--------------------------------------------------​------------------
query           | vacuum analyze pgbench_accounts
calls           | 1
total_exec_time | 136.448116
rows            | 0
hit_percent     | 99.9201915403032721

bench=# SELECT pg_stat_statements_reset(0,0,0);

bench=# 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;
-[ RECORD 1 ]---+--------------------------------------------------​---------------------------
query           | SELECT pg_stat_statements_reset(0,0,0)
calls           | 1
total_exec_time | 0.189497
rows            | 1
hit_percent     |
-[ RECORD 2 ]---+--------------------------------------------------​---------------------------
query           | SELECT query, calls, total_exec_time, rows, $1 * shared_blks_hit /          +
                |                nullif(shared_blks_hit + shared_blks_read, $2) AS hit_percent+
                |           FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT $3
calls           | 0
total_exec_time | 0
rows            | 0
hit_percent     |

F.30.6. 作者 #

Takahiro Itagaki 。Peter Geoghegan 添加了查询标准化