DeepSeek总结的在 pg_stat_statements 中诊断高基数工作负载

来源:https://pganalyze.com/blog/postgres-in-production-pg-stat-statements-deep-dive-part-6

Postgres 生产环境特别系列:在 pg_stat_statements 中诊断高基数工作负载(第 6 部分)

Ryan Booz

作者:Ryan Booz

2026年8月13日

监控与可观测性

在本期 Postgres 生产环境深度探讨特别系列的第 6 部分中,Ryan Booz 提出了一个决定 pg_stat_statements 对你有用程度的问题:你的工作负载是否具有高基数(high cardinality)?本集涵盖了这实际上意味着什么,为什么 ORM、动态 SQL 和 AI 辅助开发工具生成的独特查询比你想象的要多,在 Postgres 17 和 Postgres 18 上运行相同工作负载的并排演示,以及能够告诉你 pg_stat_statements 是否正在丢失查询调优所需数据的具体检查方法。


分享本期内容: 点击此处可在 LinkedIn 上分享本期。欢迎订阅我们的新闻通讯并关注我们的 YouTube 频道。

目录

  • 快速回顾
  • 高基数工作负载的含义
  • 独特查询的来源
  • 演示:使用 Bluebox 压垮 pg_stat_statements
  • 我们的数据库隐藏在我们的工具背后
  • 如何判断你是否面临高基数工作负载
  • 采取行动
  • 如果不采取行动会怎样
  • 关键要点
  • 下期预告
  • 我们讨论的内容
  • 文字记录

快速回顾

在前五集中,我们涵盖了 pg_stat_statements 是什么及其存储的指标(第 1 部分),是什么通过规范化(normalization)使语句变得"独特"(第 2 部分),查询文本在磁盘上的位置(第 3 部分),新指标如何存储以及旧指标如何被释放(第 4 部分),以及控制这一切的配置设置(第 5 部分)。

在所有这些内容中,我可能已经提到了 pg_stat_statements.max 设置至少 100 次,因为它对于理解你所拥有数据的有效性至关重要。本集讨论的是那些持续超出此设置的工作负载,能够识别你是否处于这种情况对于判断 pg_stat_statements 是否能帮助你进行所需的查询调优和优化非常有帮助。

高基数工作负载的含义

当我说"高基数"时,这到底意味着什么?对我来说,它意味着类似这样的情况:如果你有一个工作负载持续生成比 pg_stat_statements.max 容量更多的独特规范化查询,那么从 pg_stat_statements 的角度来看,你确实有一个高基数工作负载。该扩展无法持续保留那些可以帮助你找到最需要优化的查询的指标。

现在,我能听到你们中的许多人会说------老实说,我自己也这么说过------"我的应用程序没那么复杂。我绝不可能遇到这种情况。数据肯定在某个地方,我只是找不到而已。"嗯,情况并非总是如此。

往往是我们正在使用的工具隐藏了幕后生成的 SQL。我们知道工具在为我们抽象 SQL,但我们可能并不完全理解它对我们查询指标产生的影响。

独特查询的来源

可能是 ORM 及其为不同客户端、客户和租户生成独特 SQL 语句的方式。也许是你自己编写的自定义动态 SQL。我经常在存储过程中这样做,如果我使用 pg_stat_statements.track = all 运行,动态 SQL 会反复生成独特的语句。

也许是即席查询(ad hoc reporting)。我们都越来越多地将工具连接到我们的数据库,包括 AI 系统,这些工具在尝试导航满足请求所需的信息时会生成大量的查询。大量的即席查询可能会很快填满 pg_stat_statements

在本系列中,我们经常讨论 Postgres 17 及更低版本中的可变长度 IN 列表,更不用说具有其他相似查询的动态列选择列表了。

演示:使用 Bluebox 压垮 pg_stat_statements

我想向你展示一个简短的演示,说明压垮 pg_stat_statements 是多么容易,使用的工具是你自己也可以实际测试的。我将使用 Bluebox 示例数据库中包含的负载生成工具,这是我创建并向社区开源的一个示例数据库,用于像这样的测试和演示。

在录制此视频前大约一个小时,我在 Postgres 17 数据库和 Postgres 18 数据库上使用完全相同的设置启动了此负载生成。负载测试项目包含大约 30 种不同的场景,每种场景都是为非常特定类型的查询形态和数据请求而创建的。其中大多数包含一到两个带参数的 SQL 语句,直接对数据库执行,没有使用 ORM。在整个项目中,实际独特的文本语句总数少于 50 个。

但是其中几个,比如 batch_film_lookup,会接收一个包含 1 到 200 个电影 ID 的列表并进行查找。在 Postgres 17 或更低版本上,这很容易变成大量的独特负载:所需要的只是一个 WHERE IN 子句和大量独特的电影 ID 列表。

运行大约一个小时后,Postgres 17 在 pg_stat_statements 内部有 671 条独特语句。在 Postgres 18 上,完全相同的工作负载有 120 条独特语句。这就是我们在本系列中多次讨论的改进之一:在 Postgres 18 及以上版本中,这些 IN 列表被规范化为一条语句。

可视化这一点的另一种方法是查看带有那些 IN 列表的查询。例如,一个负载查询会根据客户 ID 列表查找数据。在 Postgres 17 上,我们可以看到数十个相同的查询,除了 WHERE IN 子句每次都显示一个独特的列表:一个有许多客户 ID,另一个有四五个,依此类推。在 Postgres 18 上,相同的查询只产生两个条目。

你可能会问,既然 Postgres 18 会折叠所有这些,为什么会有两个?部分原因与工具有关:第一次发送参数化查询时,它还必须发送值类型,当它不完全确定类型时,通常会发送一个通用类型,如 numeric。一旦收到响应,工具有时可以调整,并从那时起发送正确的数据类型,例如 integer 而不是 numeric。这通常是即使在 Postgres 18 上,你也会看到一个查询文本有几个额外条目的原因。

这个示例负载测试是查看一个看似简单的查询工作负载对 pg_stat_statements 影响的非常容易的方法,你可以使用该工具自己测试。获取 Bluebox,阅读如何启动负载测试的说明,并针对你的一个 Bluebox 示例数据库进行配置。

我们的数据库隐藏在我们的工具背后

我认为,我们比以往任何时候都更多地在经历高基数的查询工作负载,因为我们的数据库在日常开发工作中被隐藏和抽象化了。原因在现代时代就摆在我们面前:ORM 和数据访问工具允许我们使用自己的对象和对象表示法来获取我们想要的数据,让框架来编写查询,希望能尽可能高效。但我们都一次又一次地经历过,随着我们的应用程序和数据库变得更加复杂,它们可能会变得多么低效。

此外,我们现在有数十种 AI 辅助开发工具,它们基于模式以它们认为最佳的方式自由地查询数据库。即使在我自己使用其中一些工具的开发过程中,我也会看到大量 pg_stat_statements 数据被创建,因为这些工具会通过独特的单次查询来梳理特定的信息片段。如果找不到所需信息,它会不断迭代和更改查询,以尽快进入其任务的下一步。

如何判断你是否面临高基数工作负载

那么你如何诊断呢?首先,你必须知道 pg_stat_statements.max 设置为多少。很抱歉再次提及,但它确实是 pg_stat_statements 中决定你能否根据你的工作负载有效地找到所需数据的最重要设置。

其次,你离实际达到这个限制有多近?如果你的语句计数总是处于 95% 的阈值,那么几乎可以肯定释放(deallocation)一直在发生。你可以尝试重置 pg_stat_statements 并观察它是否很快重新填满。我曾与一些客户合作,他们将其设置为 5,000 甚至 10,000,当他们重置指标时,哈希表在不到 30 分钟内就重新填满了。这是一个很好的指标,表明你的工作负载有多大,以及你能在信息再次消失之前多快地使用这些信息。

第三,释放计数器(deallocation counter)是否在攀升?当你查询 pg_stat_statements_info 时,你是否看到这个数字时不时地上升,即使每天只上升一两次,更不用说每小时一两次了?

第四,你多久会搜索一次在 pg_stat_statements 中不存在的查询文本?我经常听到人们问:"我知道我的代码中有一个查询在运行。为什么它不在 pg_stat_statements 中?"简短而简单的答案是,"它很可能丢失了"。如果你持续尝试根据你已知的文本前几行来查找一个语句,却找不到它,那么它被释放的速度比你获取其指标的速度还要快。这就是高基数工作负载。

还有一个最后的测试:你的 top 查询。你认为的 top 查询可能会根据你想要实现的目标而变化,但我们通常从总执行时间开始,即自 pg_stat_statements 开始跟踪以来,一个查询执行所花费的总时间。如果你按此排序,并且前十名变化相当频繁,而你认为你的工作负载是相当一致的,那么你可能有一个高基数工作负载。

采取行动

如果你确实有高基数工作负载,那么确实是时候采取行动了。你不能只希望这个问题会自行解决。

首先,回去观看第五集,我们回顾了 pg_stat_statements 中的所有设置,那些可以动态更改的设置和那些需要重启的设置。接下来,考虑升级到 Postgres 18,这是我在那一集结尾提出的建议之一。

然后是检查你的 ORM 和 AI 工具中的问题。与你的开发团队沟通:帮助他们理解,当这些工具提出查询建议时,有一些需要寻找的模式可能会带来问题。

老实说,我建议你记录下 pg_stat_statements 似乎缺乏你需要的信息的时间。这有什么一致性吗?也许每个周一早上你去找查询,但你找不到,因为大型数据转换任务在周末运行,洪水般地填满了 pg_stat_statements,把你上周想用来识别问题的信息挤出去了。

如果不采取行动会怎样

最终,如果你不采取行动,在 Postgres 中进行调优就会变得困难得多。你没有找到有问题查询所需的全部信息。你的历史记录变得更短,因此即使你认为自己修复了某些问题,也很难确定修复是否达到了预期效果。随着时间的推移,你所做的优化决策会变得不那么可信,因为你永远不确定它们是否真的产生了预期的影响。

关键要点

  • 高基数工作负载意味着你的查询超出了你的容量。 如果你的工作负载持续生成比 pg_stat_statements.max 所能容纳的更多的独特规范化查询,那么 pg_stat_statements 就无法保留你调优所需的指标。
  • 独特性通常来自工具。 ORM 生成针对每个租户的语句、自定义动态 SQL(尤其是在使用 track = all 时)、即席查询、AI 辅助开发工具以及 Postgres 17 及更低版本上的 IN 列表。
  • Postgres 18 带来了显著的差异。 相同的 1 小时 Bluebox 工作负载在 Postgres 17 上产生了 671 条独特语句,在 Postgres 18 上产生了 120 条,这要归功于 IN 列表规范化。
  • 有五项检查可以诊断它。 了解你的 max 设置;观察重置后表重新填充的速度;监控 pg_stat_statements_info 中的释放计数器;检查你已知正在运行的查询是否丢失;以及观察按总执行时间排序的前 10 名是否频繁变动。
  • 设置可以缓解问题,但原因在于你的应用程序。 重新审视第 5 集的设置,考虑使用 Postgres 18,并与你的开发团队合作处理你工具产生的查询模式。

下期预告

在我们的最后一集中,我们将讨论使用 pg_stat_statements 的几种方法,包括我们推荐的一些查询,以便你能更有效地找到对工作负载影响最大的查询。欢迎下次收看我们对 pg_stat_statements 深度探讨的第七集。

我希望这个系列能帮助你更好地理解 Postgres 生态系统中这个最基本的工具之一。欢迎订阅我们的 YouTube 频道、注册我们的新闻通讯或在 LinkedIn 上关注我们,以获取新剧集的更新!

我们讨论的内容

  • pg_stat_statements 文档
  • pg_stat_statements_info 视图
  • Bluebox 示例数据库
  • pg_stat_statements 深度探讨系列的早期部分:
    • 第 1 部分:它是什么,不是什么
    • 第 2 部分:是什么让语句变得独特
    • 第 3 部分:你的查询文本实际存储在哪里
    • 第 4 部分:pg_stat_statements 如何决定保留什么
    • 第 5 部分:配置 pg_stat_statements 以减少释放
相关推荐
ACP广源盛139246256732 小时前
WAIC2026 国产算力浪潮下@ACP#IX8024 在算力矩阵中的定位与落地场景
大数据·数据库·人工智能·嵌入式硬件·线性代数·矩阵
snow@li2 小时前
MySQL:库表设计完整规范与实战方案
数据库·mysql
ClouGence2 小时前
数据库管理工具 CloudDM 4.1.0 发布,支持达梦、Cloudberry
数据库·开源
小白勇闯网安圈2 小时前
Django 模板复用、ORM 查询与多对多关系
数据库·python·django
TELL5213 小时前
帮我生成对应的sql 以及数据库-deepseek提示词
数据库·sql
能年玲奈喝榴莲牛奶3 小时前
系统规划与管理师-第一章-考点记忆
大数据·数据库·软考·系统规划与管理师·系规
SatanII3 小时前
mariadb
数据库·mariadb
大千UI工场4 小时前
时序数据库对数字孪生的作用
数据库·ui·时序数据库·前端开发·b端管理系统
Tongzhi20264 小时前
通芝科技无感考勤一体机:软硬一体,开箱即用
数据结构·数据库·科技·算法·均值算法·数据库开发