Shaun Thomas:让我们构建一个用于估算内存使用量的Postgres扩展!

Shaun Thomas:让我们构建一个用于估算内存使用量的Postgres扩展!

💡 原文英文,约4000词,阅读约需15分钟。
📝

内容提要

本文介绍如何构建Postgres扩展querymem,用于预测查询内存消耗。通过解析查询、生成执行计划并遍历节点,累加work_mem和hash_mem_multiplier估算峰值内存。扩展支持GUC配置,可自动记录或阻止超限查询。作者强调源码是最终文档,鼓励开发者探索Postgres内部机制。

🔎

延伸解读

为什么需要估算查询内存

Postgres 的 work_mem 是按操作分配的,而不是按查询。一个查询中的排序、哈希等节点各自获得独立的 work_mem 配额,因此复杂查询可能消耗远超预期的内存。本文通过构建扩展来估算最坏情况下的内存使用,帮助用户理解 work_mem 设置的实际影响,并为后续优化提供依据。

扩展的工作原理

querymem 扩展通过调用 Postgres 内部的解析器和规划器,获取查询的执行计划,然后遍历计划节点,累加每个节点的内存系数(普通节点为 1,哈希节点为 hash_mem_multiplier),最后乘以 work_mem 得到估算值。这种方法直接利用优化器的真实输出,而非模拟或解析 EXPLAIN 文本,因此结果具有较高的参考价值。

实际应用与限制

扩展提供了两个 GUC 参数:querymem.log_size 和 querymem.max_query_size,分别用于记录和阻止超过阈值的查询。但当前实现存在一些限制,例如未考虑并行计划,且对某些节点(如 CTE)的估算可能不准确。作者也指出,直接调用 planner 可能存在内存泄漏风险,需要进一步优化。

从源码中学习

本文强调,Postgres 的用户手册并未涵盖扩展开发所需的内部机制,真正的文档藏在源码的 README 文件和头文件注释中。通过阅读源码,开发者可以理解解析、规划、节点遍历等核心概念,并学会如何正确使用钩子(hook)机制。这种探索方式虽然耗时,但能带来更深的理解。

Q&A

如何构建一个Postgres扩展来估算查询内存使用量?

构建一个名为querymem的Postgres扩展,通过解析查询、生成执行计划并遍历节点,累加work_mem和hash_mem_multiplier来估算峰值内存。扩展支持GUC配置,可自动记录或阻止超限查询。

Postgres中work_mem和hash_mem_multiplier是如何影响查询内存的?

work_mem是每个查询操作(如排序、哈希)可用的最大内存,每个节点独立分配。hash_mem_multiplier(默认2.0)用于计算哈希表的内存限制,因此哈希节点的内存消耗是work_mem的倍数。

querymem扩展是如何估算查询内存的?

querymem通过解析查询生成执行计划,然后遍历计划节点,对每个节点累加1.0(普通节点)或hash_mem_multiplier(哈希节点),最后乘以work_mem得到最坏情况下的内存估算。

如何设置querymem扩展的日志和阻止阈值?

通过GUC参数querymem.log_size和querymem.max_query_size设置。log_size用于记录超过阈值的查询,max_query_size用于阻止超过阈值的查询。设置后需执行pg_reload_conf()生效。

querymem扩展如何自动监控查询?

通过安装ExecutorStart_hook,在每次查询执行前自动估算内存,并根据配置记录或阻止超限查询。

构建querymem扩展需要哪些开发环境?

需要Postgres源码或开发头文件,以及构建工具链(如build-essential、flex、bison等)。推荐使用Docker基于postgres:18镜像,包含所有依赖。

querymem扩展的源码在哪里可以获取?

源码在GitHub上,仓库名为querymem。

🏷️

标签

➡️

继续阅读