|
| 1 | +# How to work with pg_stat_statements, part 3 |
| 2 | + |
| 3 | +## 第三类衍生指标:百分比 |
| 4 | + |
| 5 | +现在,让我们来研究第三类衍生指标:某个查询组 (标准化查询或更大的组,例如"特定用户的所有语句"或"所有 `UPDATE` 语句") 在整个工作负载中所占的百分比,基于指标 M。 |
| 6 | + |
| 7 | +如何计算:首先,针对所有查询组应用基于时间的微分 (如第一部分中讨论的 `dM/dt`),然后将特定查询组的值除以所有查询组的总和。 |
| 8 | + |
| 9 | +## %M 的可视化与解读 |
| 10 | + |
| 11 | +虽然 `dM/dt` 给我们提供了绝对值,如每秒调用次数或 `GiB/sec`,但 `%M` 值是相对指标。这些值帮助我们识别工作负载中各个方面的"主要参与者" — 频率、时间、IO 操作等。 |
| 12 | + |
| 13 | +通过分析相对值,我们可以理解每个优化方向的潜在收益大小,并优先处理最具潜力的优化。例如: |
| 14 | + |
| 15 | +- 如果 QPS 的绝对值看起来很高 — 比如 1000 次调用/秒 — 但它仅占整体工作负载的 `3%`,那么减少这一查询不会带来太大的收益。如果我们关心的是 QPS,我们需要优化其他查询组。 |
| 16 | +- 然而,如果我们有 1000 次调用/秒,并且它占了整体工作负载的 `50%`,那么单次优化步骤 — 比如将其减少到 10 次调用/秒 — 这将帮助我们减少几乎一半的 QPS。 |
| 17 | + |
| 18 | +在较大的系统中处理比例值的一种方法是对较大比例值做出反应,将相应的查询组作为优化候选项。例如,在具有大量查询组的系统中,可能有必要使用以下方法: |
| 19 | + |
| 20 | +- 定期针对某些指标 (例如 `calls`、`total_exec_time`、`total_plan_time`、`shared_blks_dirtied`、`wal_bytes`) 构建 Top-10 列表,显示具有最大 `%M` 值的查询组。 |
| 21 | +- 如果某个查询组在某些指标上是主要贡献者 — 例如,>20% — 则应考虑将此查询作为优化的候选项。例如,在大多数情况下,我们不希望单个查询组占据 `total_exec_time` 总和的 1/2 ( total total_exec_time”,抱歉使用了赘语)。在某些情况下,可以决定某个查询不需要优化 — 在这种情况下,我们将该组标记为排除项,并在下次分析中跳过它。 |
| 22 | + |
| 23 | +对比例的分析也可以在监控系统中通过可视化方式隐式完成:观察 `dM/dt` 图表 (例如 QPS,每秒块命中次数),我们可以直观地理解哪个查询组在整个工作负载中对特定指标 `M` 的贡献最大。然而,为此,图表需要"[堆叠式](https://en.wikipedia.org/wiki/Bar_chart#Grouped_.28clustered.29_and_stacked)"显示。 |
| 24 | + |
| 25 | +如果我们处理两个快照,那么明确获取这些值是有意义的。此外,出于可视化目的,为我们分析的每个指标绘制一个饼图也是有意义的。 |
| 26 | + |
| 27 | +## %M 示例 |
| 28 | + |
| 29 | +- `%M`,`M` 是调用次数 `calls` — 这为我们提供了 QPS 的比例。例如,如果我们通常有约 `10k QPS`,但如果某个查询组负责约 `7k QPS`,这可能被认为是不正常的,需要在客户端 (通常是应用代码) 进行优化。 |
| 30 | +- `%M`,`M` 是 `total_plan_time + total_exec_time` — 服务器处理特定查询组所花费时间的百分比。例如,如果绝对值是 `20 秒/秒` (负载相当大的系统——Postgres 每秒需要花费 20 秒来处理查询),并且某个查询组占了该指标的 75%,这意味着我们需要重点优化该查询组。优化方法: |
| 31 | + - 如果 QPS (`calls/second`) 很高,那么首先我们需要减少它。 |
| 32 | + - 如果平均延迟 (`total_exec_time`,或较少见的 `total_plan_time` 或两者) 较高,那么我们需要使用 `EXPLAIN` 和 `EXPLAIN (ANALYZE, BUFFERS)` 进行微观优化。 |
| 33 | + - 在某些情况下,我们需要结合两种优化方向。 |
| 34 | +- `%M`,`M` 是 `shared_blks_dirtied` — 分析查询组在缓冲池中执行的更改所占百分比。这种分析可以帮助我们识别工作负载中的写密集部分,并找到减少检查点次数和磁盘 IO 量的机会。 |
| 35 | +- `%M`,`M` 是 `wal_bytes` — 写入 WAL 的字节数百分比。这帮助我们识别优化 WAL 生成量最有影响的查询组。 |
| 36 | + |
| 37 | +## 总结:三大宏观优化目标及其使用方法 |
| 38 | + |
| 39 | +现在,通过我们在前两部分中描述的分析方法,让我们仅基于一个指标 `total_exec_time` 来考虑三种常见的宏观优化类型。 |
| 40 | + |
| 41 | +理解这三种方法 (然后将这种逻辑应用于其他指标) 可以帮助你理解如何设计监控仪表盘。 |
| 42 | + |
| 43 | +- 宏观优化旨在减少资源消耗。在这里,我们首先希望减少 CPU 利用率、内存和磁盘 IO 操作。为此,我们需要使用 `dM/dt` 类型的衍生指标 — Postgres 每秒处理查询所花费的秒数。减少这一指标 (整个服务器的聚合 "total" 值,以及在其中起重要作用的前 N 个组) 是我们的目标。此外,我们可能还想考虑其他指标,例如 `shared_blks_***`,但时间可能是最好的起点。这种优化可以帮助我们进行容量规划、基础设施成本优化,并降低资源耗尽的风险。 |
| 44 | +- 宏观优化旨在改善用户体验。在这里,我们希望用户有最佳体验,因此在 OLTP 场景中,我们应重点关注平均延迟,并以减少它们为目标。因此,我们将使用 `dM/dc` — 每个查询平均持续的秒数 (或毫秒)。如果在上一种优化类型中,我们希望在监控系统中看到按 `dM/dt` 值 (以 `seconds/second` 为单位) 排序的前 N 个查询组,这里我们希望按平均延迟 (以秒为单位) 排序的前 N 个组。通常,这会给我们一个非常不同的查询集 — 这些查询可能 QPS 较低,但延迟最差,最让用户感到烦恼。在某些情况下,在这种分析中,我们可能想排除 QPS 较低的查询组 (例如 QPS < 1 call/sec 的那些) 或排除一些工作负载部分,如数据导出活动,它们不可避免地有较长的延迟。 |
| 45 | +- 宏观优化旨在平衡工作量。这是较为罕见的一种优化类型,但这正是 %M 发挥作用的地方。开发我们的应用程序时,我们可能想不时检查 `total_exec_time + total_plan_time` 的前 N 个百分比,并识别占比最大的查询组 — 正如我们之前讨论的那样。 |
| 46 | + |
| 47 | +附加内容:播客集 |
| 48 | + |
| 49 | +相关的 Postgres.FM 播客集: |
| 50 | + |
| 51 | +- [Intro to query optimization](https://postgres.fm/episodes/intro-to-query-optimization) |
| 52 | +- [102 query optimization](https://postgres.fm/episodes/102-query-optimization) |
| 53 | +- [pg_stat_statements](https://postgres.fm/episodes/pg_stat_statements) |
| 54 | + |
| 55 | +--- |
| 56 | + |
| 57 | +这就是我们目前对 pgss 的讨论。当然,这不是完整的指南,我们可能会在未来再次讨论这个重要的扩展。如有任何问题或其他反馈,请告诉我! |
0 commit comments