|
| 1 | +# How to work with pg_stat_statements, part 2 |
| 2 | + |
| 3 | +昨天我们讨论了使用 pg_stat_statements (pgss) 的一些基础知识,以及第一组衍生指标 `dM/dt`——基于时间的微分。今天我们将重点关注第二组指标:`dM/dc`,其中 c 表示调用次数 (pgss 中的 `calls` 列)。 |
| 4 | + |
| 5 | +## 衍生指标2. 基于调用次数的微分 |
| 6 | + |
| 7 | +这一组指标的重要性不亚于基于时间的微分,因为它可以为你提供工作负载的系统化视图,是查询性能宏观优化的有力工具。 |
| 8 | + |
| 9 | +这组指标帮助我们理解每个查询组的平均查询特性。 |
| 10 | + |
| 11 | +不幸的是,许多监控系统忽视了这种衍生指标。一套好的系统应该展示全部或至少大部分此类指标,并显示这些值随时间变化的图表 (`dM/dc` 时间序列)。 |
| 12 | + |
| 13 | +获取此类衍生指标的结果非常简单: |
| 14 | + |
| 15 | +- 计算两个 pgss 快照之间的 M 值 (正在研究的指标) 的差值:`M2 - M1` |
| 16 | +- 然后,不使用时间戳,而是获取 "calls" 值的差值:`c2 - c1` |
| 17 | +- 接着计算 `(M2 - M1) / (c2 - c1)` |
| 18 | + |
| 19 | +让我们看看通过这种方式获得的各种衍生指标的意义: |
| 20 | + |
| 21 | +- `dM/dc`,当 `M` 是 `calls` 时 — 这是一种退化情形,该值始终为1 (调用次数除以相同的调用次数)。 |
| 22 | +- `dM/dc`,当 `M` 是 `total_plan_time + total_exec_time` 时 — 这是某个特定 pgss 查询组中查询的平均执行时间,这是查询性能观察中的一个极其重要的指标。它也可以称为 "查询延迟"。当应用于 pgss 中所有标准化查询的聚合值时,其意义是 "服务器上平均查询延迟" (有两个重要的注意事项:pgss 并不追踪失败的查询,并且由于 `pg_stat_statements.max` 限制,有时数据可能偏斜)。Postgres 的主要累积统计信息系统并不提供这种信息 — `pg_stat_database` 仅在 `track_io_timing` 启用时才会跟踪一些时间指标,如 `blk_read_time` 和 `blk_write_time`,在 PG14+ 中还有 `active_time`,但它不包含语句数量的信息,只记录事务数量 (`xact_commit` 和 `xact_rollback`);在某些情况下,我们可以从其他来源获得这些数据 — 例如,pgbench 在用于基准测试时会报告这些数据,pgBouncer 也会报告事务和查询的平均延迟,但在常规情况下,在观测工具中,pgss 被认为是获取查询延迟信息的最通用方式。其重要性怎么估计都不为过 — 例如: |
| 23 | + - 如果我们知道通常情况下,平均查询持续时间 <1 ms,那么任何升至 10 ms 的情况都应被视为一个严重事件 (如果这是在部署后发生的,应该重新考虑或回滚该部署)。在故障排除时,它还能帮助我们进行分段分析,确定哪些特定查询组导致了延迟的升高 — 是所有查询组,还是只有特定的一些? |
| 24 | + - 在许多情况下,这可以被视为大型负载测试和基准测试中最重要的指标 (例如:比较 PG 15 和 PG 16 的平均查询持续时间,以便为升级到 PG 16 做准备)。 |
| 25 | +- `dM/dc`,当 `M` 是 `rows` 时——这是查询组中查询返回的平均行数。对于 OLTP 场景来说,具有较大值的查询组 (起始值为几百或更多,具体取决于情况) 应进行审查: |
| 26 | + - 如果这是有意为之 (例如,数据导出),则无需采取行动; |
| 27 | + - 如果这是面向用户的查询,并且与数据导出无关,那么可能存在错误,例如缺少 `LIMIT` 和适当的分页,应该修正这些查询。 |
| 28 | +- `dM/dc`,当 `M` 是 `shared_blks_hit + shared_blks_read` 时 — 这是查询组中缓冲池的平均 "命中数" + "读取数"。可以将其转换为字节进行分析:例如,`500,000` 次缓存命中和读取转换为 `500000 GiB * 8 / 1024 / 1024 ≈ 3.8 GiB`,这是单个查询中的一个显著数值,尤其是在查询目标仅仅返回一行或几行的情况下。对于较大的值,应考虑对查询进行优化。补充说明: |
| 29 | + - 在许多情况下,单独分析命中和读取的情况也是有意义的 — 例如,某些 pgss 查询组中的查询可能不会导致高磁盘 IO 和页面缓存读取,但在缓存池中的命中数非常多,尽管所有数据都缓存于缓存池中,但其性能仍不理想。 |
| 30 | + - 要获取实际的磁盘 IO 数值,建议使用 [pg_stat_kcache](https://github.com/powa-team/pg_stat_kcache)。 |
| 31 | + - 如果某个查询组的此指标值突然发生变化,并且这种变化持续了一段时间,可能是执行计划发生了变化,需要进一步研究。 |
| 32 | + - 高层聚合值也是观察的重点,例如回答类似 "该服务器上所有查询平均读取了多少 MiB?" 的问题。 |
| 33 | +- `dM/dc`,当 `M` 是 `wal_bytes`(PG13+)时 — 这是查询组生成的平均 WAL 大小,单位是字节。它有助于识别哪些查询组对 WAL 的生成贡献最大。所有 pgss 记录的"全局"聚合值代表了服务器上所有语句的平均 WAL 字节数。对于 `dM/dc`(`M` 是 `wal_fpi`),在检查点调优场景中,跟踪其变化非常有用:当 `full_page_writes = on` 并且增加检查点之间的距离时,我们应该观察到该值的下降,研究不同的 pgss 组也可能很有意义。 |
| 34 | + |
| 35 | +--- |
| 36 | + |
| 37 | +明天我们将完成关于 pgss 相关的第三步教程。 |
0 commit comments