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

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

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

内容提要

本文介绍如何构建Postgres扩展querymem,用于预测查询内存消耗。通过解析查询、生成执行计划并遍历节点,累加work_mem和hash_mem_multiplier估算峰值内存。扩展支持GUC配置,可自动记录或阻止超限查询。文章强调从源码学习Postgres内部机制,并演示了实际测试结果。

🔎

延伸解读

为什么需要估算查询内存

Postgres 的 work_mem 是按操作分配的,而不是按查询。一个查询中如果有多个排序、哈希等节点,每个节点都会获得独立的 work_mem 分配,因此实际内存消耗可能远超预期。本文通过构建扩展来估算最坏情况下的内存使用,帮助用户理解查询的内存需求,并为设置 work_mem 提供参考。

从源码学习 Postgres 内部机制

构建该扩展需要深入 Postgres 源码,使用 raw_parser、transformTopLevelStmt、planner 等内部函数。这些函数在用户手册中没有详细示例,但源码中的 README 文件和头文件注释提供了关键线索。通过阅读源码,可以理解查询解析、分析和计划生成的过程,这是开发复杂扩展的基础。

扩展的实际应用与限制

querymem 扩展可以估算查询内存,并可通过 GUC 配置自动记录或阻止超限查询。但当前实现存在一些限制,例如未考虑并行计划,且对某些节点类型的计数可能不准确(如文中提到的额外节点导致估算偏差)。此外,直接调用 planner 可能存在内存泄漏风险,需要进一步优化。

Q&A

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

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

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

querymem通过遍历执行计划中的每个节点,为普通节点累加1.0,为哈希节点累加hash_mem_multiplier(默认2.0),然后将总和乘以work_mem得到最坏情况下的内存估计。

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

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

querymem扩展如何自动记录或阻止超限查询?

通过定义GUC参数querymem.log_size和querymem.max_query_size,并设置ExecutorStart_hook,在每次执行前估算内存,超过log_size则记录日志,超过max_query_size则报错阻止执行。

querymem扩展的测试结果如何?

测试显示,简单顺序扫描估计为4MB,带排序的查询为8MB,带哈希连接的查询为28MB,带物化CTE的查询为57MB,与理论计算一致。

构建querymem扩展时,如何从源码中学习Postgres内部机制?

文章强调,当文档不足时,应阅读源码中的README文件、头文件注释和contrib目录中的示例,例如parser.c、optimizer/README等,以理解解析、规划和节点遍历等机制。

🏷️

标签

➡️

继续阅读