深入理解 PostgreSQL Planner:简化扫描路径与查询计划

AI Agent开发实战:从核心范式到工程部署的完整学习路线 AI Agent 作为大模型落地应用的关键形态,正从概念验证走向规模化工程实践。对于希望在2026年前后进入这一领域的开发者而言,最大的挑战并非理解单个技术点,而是如何构建一个系统性的知识体系,将分散的模型调用、工具集成、状态管理和业务逻辑串联成一个稳定、可维护的智能体系统。本文旨在为计划转行或深度切入AI Agent开发的工程师、全栈开发者及技术决策者,提供一条从基础认知到项目实战的保姆级学习路线。我们将遵循“理解核心范式 -> 掌握基础工具链 -> 构建单体Agent -> 设计复杂工 阅读详情

引言

当向 PostgreSQL 发送查询时,查询通常会经过几个处理阶段,并最终返回结果。这些阶段如下所示:

  • 解析(Parse)
  • 分析(Analyze)
  • 重写(Rewrite)
  • 计划(Plan)
  • 执行(Execute)

在本文中,我们将仅关注“计划”阶段或“规划器(Planner)”模块,因为这是最有趣或最复杂的阶段。我将分享我对规划器模块的理解,并探讨它如何处理一个简单的顺序扫描。

规划器的目标非常简单:从可用路径中识别出最快的“路径”,并根据此路径制定一个“计划”,以便“执行器”模块在下一阶段执行它。然而,识别最快的“路径”就是造成规划器复杂的原因。

注:本文基于 PostgreSQL 16 撰写。

一切从哪里开始

在 postgres.c 中的 exec_simple_query() 函数是查询处理阶段的起点。我们将关注它进入 pg_plan_query() 后发生的事情。下面我只会提到它会调用的重要函数。

file

在 pg_plan_query() 背后发生了什么?

实际上,发生了很多事情,例如:

  • 识别子查询、分区表、外部表、连接等
  • 通过表访问方法估算所有涉及的表的大小
  • 识别完成查询的所有可能路径
  • 顺序扫描、索引扫描、TID 扫描、并行工作线程等
  • 在所有路径中,找到最佳路径,通常是成本最低的
  • 根据此路径制定计划

以一个简单的 SELECT 查询为例,该查询只涉及一个表,没有连接或子查询,下面是大致的调用栈:

file

这个调用栈图进行了极简化,但展示了规划器模块的几个关键元素。带有蓝色星号的块将在下一节中详细解释。

set_base_rel_sizes()

顾名思义,这是估算所有关系(表、视图、索引等)大小的主要入口。大小包括估算的行数(元组)和列数。通常需要通过“堆访问方法”来获取这些信息,这样它就可以访问“缓冲区管理器”和“存储管理器”,以提供对大小的估算。

总大小将是所有相关表的大小。这对后续的“成本估算”阶段非常重要。

set_base_rel_pathlist()

对于一个简单表的顺序扫描,程序将在此处结束。对于更复杂的查询,将有不同的路径构建技术。有关其他路径构建技术,请参阅 allpaths.c 中的 set_rel_pathlist()。

当前,默认添加了 4 种扫描路径:

  • 顺序扫描(Sequential Scan)
    • 顺序扫描所有内容
  • 部分顺序扫描(Partial Sequential Scan)
    • 由于要通过“聚合”节点(在下一阶段处理)进行聚合,因此被标记为“部分”。这本质上意味着并行顺序扫描。
    • 仅在关系或查询被认为是并行安全时添加
  • 索引扫描(Index Scan)
    • 如果表有索引,它可以被认为是一个潜在路径
  • TID 扫描(TID Scan)
    • 如果查询包含范围限制子句(如 WHERE ctid > '(1,30)' AND ctid < '(30,5)'),则可以选择 TID 扫描

所有这些路径都涉及一些成本,通过元组或页面的数量以及每个元组/页面的成本因子来估算,成本因子配置如下:

# Planner Cost Constants

- `seq_page_cost` = 1.0                    # 任意尺度
- `random_page_cost` = 4.0                 # 与上述相同的尺度
- `cpu_tuple_cost` = 0.01                  # 与上述相同的尺度
- `cpu_index_tuple_cost` = 0.005           # 与上述相同的尺度
- `cpu_operator_cost` = 0.0025             # 与上述相同的尺度
- `parallel_setup_cost` = 1000.0           # 与上述相同的尺度
- `parallel_tuple_cost` = 0.1              # 与上述相同的尺度

不同的路径方法有不同的成本计算,它们会调用以下方法来计算“启动成本”和“运行成本”:

  • cost_seqscan()
  • cost_indexscan()
  • cost_tidscan()

你可以通过调整这些成本来影响规划器在选择最理想路径时的决策。例如,如果你希望规划器更多地使用并行扫描,可以考虑降低并行扫描元组的成本,例如将 parallel_tuple_cost 设置为更小的值,如 0.001。

add_path 被调用来将路径添加到潜在路径列表中,但请记住,规划器的路径构建机制具有驱逐机制。这意味着如果我们打算添加一个明显优于当前路径的新路径,规划器可能会丢弃所有现有路径,接受新的路径。类似地,如果要添加的路径明显较差,它将不会被添加。

如果规划器认为并行顺序扫描是安全的,则会调用 add_partial_path。这种顺序扫描被称为“部分”扫描,因为它需要收集和聚合数据以形成最终结果,因此会产生额外的成本,那么就会造成并行性并不总是理想的结果。这里有个经验法则:

  • 如果 PostgreSQL 必须扫描大量数据,但我们只需要其中一小部分,使用并行扫描可以提高效率;
  • 如果 PostgreSQL 必须扫描大量数据,而且大部分数据都是我们需要的,并行扫描可能会更慢。

generate_gather_paths

如果已经添加了某些部分路径(通常是顺序扫描子路径),则会调用该函数。这个例程添加了一种新的路径类型“gather”,它包含一个子路径“顺序扫描”。聚合路径需要考虑每个子路径的成本,以及从并行工作线程获取元组并聚合数据的成本。

get_cheapest_fractional_path 和 create_plan

一旦所有潜在路径候选项被添加后,调用这个函数来选择最便宜的路径,即具有最低总成本的路径。然后,这个选择的路径将被传递给 create_plan,在这里路径(及其子路径,如果有的话)将被递归创建,并形成最终的计划结构,供执行器理解和执行。

审查计划

我们可以在查询前使用 EXPLAIN ANALYZE 来检查规划器选择的最便宜计划及其成本细节。以下示例是一个查询计划,它包含一个名为“gather”的主计划,里面有一个名为“顺序扫描”的部分计划,并且有 2 个工作线程。你可以通过箭头(->)来判断哪个是子路径。

postgres=# explain analyze select * from test where a > 500000 and a <600000;
                          QUERY PLAN
------------------------------------------------------------
 Gather  (cost=1000.00..329718.40 rows=112390 width=36) (actual time=62.362..5106.295 rows=99999 loops=1)
   Workers Planned: 2
   Workers Launched: 2
   ->  Parallel Seq Scan on test  (cost=0.00..317479.40 rows=46829 width=36) (actual time=58.020..3416.544 rows=33333 loops=3)
         Filter: ((a > 500000) AND (a < 600000))
         Rows Removed by Filter: 13300000
 Planning Time: 0.489 ms
 Execution Time: 5110.030 ms
(8 rows)

如果规划器选择顺序扫描主路径且没有任何子路径,查询计划将如下所示:

postgres=# explain analyze select * from test where a > 500000;
                          QUERY PLAN
------------------------------------------------------------
 Seq Scan on test  (cost=0.00..676994.40 rows=39571047 width=6) (actual time=0.011..7852.896 rows=39500000 loops=1)
   Filter: (a > 500000)
   Rows Removed by Filter: 500000
 Planning Time: 0.115 ms
 Execution Time: 9318.773 ms
(5 rows)

总结

PostgreSQL 规划器的内部机制较为复杂,但通过本文解析,您应已掌握其核心运行逻辑。若您需要针对特定场景定制优化查询性能(例如调整代价模型参数)或扩展功能(如引入新的扫描路径策略),至少能基于现有原理明确切入点。

PostgreSQL——查询优化——预处理 2021SC@SDUSC 目录概述查询优化pg_plan_queries函数pg_plan_queries函数调用的—— **pg_plan_query函数**pg_plan_queries函数返回的—— **PlannedStmt结构体**pg_plan_query函数调用的——**planner函数**standard_planner函数调用的——**subquery_planner函数**subquery_planner函数返回的——**Plan结构体** 概述 我负责的PostgreSQL代码部分: 阅读详情

相关推荐

如何监控和分析 PostgreSQL 中的查询执行计划?

监控和分析 PostgreSQL 中的查询执行计划是数据库性能优化的关键步骤。通过深入理解执行计划的各个元素,结合实际的业务需求和数据特点,采取合适的优化策略,可以显著提高数据库的性能,为应用程序提供更快速和高效的服务。希望以上内容能帮助您全面了解如何在 PostgreSQL 中监控和分析查询执行计划,并有效地进行性能优化。🎉相关推荐🍅关注博主🎗️带你畅游技术世界,不错过每一次成长机会!📢学习做技术博主创收📚领书:PostgreSQL 入门到精通.pdf📙PostgreSQL 中文手册。

技术笔记 2327

pg数据库进行查询计划分析

在 PostgreSQL 数据库中,可以使用 EXPLAIN 关键字来获取查询计划。EXPLAIN 可以让你查看 PostgreSQL 的查询计划。

qq_34322136的博客 672

PostgreSQL查询语句执行过程中的主要函数源代码分析

PostgresQL查询语句执行过程中的主要函数,包括语句分析、查询重写、执行和输出

weixin_47895938的博客 622

PostgreSQL源码学习笔记(6)-查询编译

当PG的后台进程Postgres接收到查询命令后,需要先将其传递到查询分析模块,进行词法,语法与语义分析。对于用户的查询命令,比如SELECT,CREATE TABLE以及一些简写的命令如"\dt",“\d”(这些简单命令会首先被转化为SELECT的语句),PG需要为其构建一颗原始解析树,然后交给查询重写模块。查询重写模块根据解析树以及一些指定参数执行解析分析以及规则重写得到查询树,最后将查询树输入到计划模块得到计划树。

爱敲键盘的吉他手 1509

全国一等奖数据库内核全拆解:B+树、MVCC与执行器设计实战

数据库内核是存储、计算与并发控制的交汇点,其核心能力往往体现在B+树索引、MVCC快照隔离和火山模型执行器等基础组件的协同设计上。理解这些原理,不仅有助于掌握数据库的底层运行机制,更能为SQL性能优化、事务一致性保障提供工程化思路。在真实场景中,无论是分析型查询的Join重排,还是高并发写入下的版本链回收,都依赖对索引结构、锁顺序和日志落盘策略的深入理解。本文基于一个荣获全国一等奖的数据库管理系统设计赛作品,从存储引擎到执行器逐层拆解其架构选型与踩坑记录,完整呈现了从零实现一个可运行数据库的工程路径,适合对

weixin_33882452的博客 388

退火朗之万动力学采样

退火朗之万动力学采样(Simulated Annealing Langevin Dynamics Sampling)结合了退火技术和朗之万动力学,是一种用于分子模拟和统计物理中的计算方法。这种方法可以帮助系统从局部最小值中逃逸,以找到全局最小值或进行有效的配置空间探索。

weixin_39699362的博客 1951

二、postgre数据库SQL优化:查看执行计划

sql优化是一项必备技能,为了优化sql任务,则需要明确需要优化的内容。除了经验之外,可以借助工具,查看sql执行过程中的耗时环节,从而针对性的进行优化,本文即为对执行计划的一些基本信息进行了总结学习。

积跬步,慕至千里的博客 6849

告别手动维护!教你用SAP BAPI批量更新生产订单BOM组件(CO02工单)

本文详细介绍了如何利用SAP BAPI实现生产订单BOM组件的批量更新,解决传统手工操作(如CO02工单)效率低下的问题。通过核心函数解析和批量处理框架设计,帮助用户大幅提升工作效率,降低错误率,适用于物料主数据变更、季节性配方调整等场景。

weixin_30844577的博客 561

PostgreSQL 的查询计划(Query Plan)及如何读取它

查询计划是数据库系统用于执行 SQL 语句的一个详细计划。它描述了数据库如何获取所需的数据,包括使用哪些索引、如何连接表、读取数据的顺序等。查询计划是数据库优化器生成的,它基于 SQL 查询的结构、表的统计信息、索引的存在等因素进行决策。解析:将 SQL 查询解析成内部表示。重写:根据规则修改查询以优化它。规划:生成执行计划并选择最佳的执行策略。执行:根据生成的执行计划读取和处理数据。理解 PostgreSQL 的查询计划对于优化数据库性能至关重要。通过使用EXPLAIN和。

My_wife_QBL的博客 2162

交流异步机VVVF变频控制simulink/matlab仿真分析

VVVF,是Variable Voltage and Variable Frequency的缩写, 意为:可变电压、可变频率,也就是变频调速系统。 VVVF控制的逆变器连接电机,通过同时改变频率和电压,达到磁通恒定(可以用反电势/频率近似表征)和控制电机转速(和频率成正比)的目的,所以多应用在变频器中,属于工业自动化领域。

Ezekiel_Mok的博客 4213

手把手教你用SAM模型实现精准图像分割:从环境配置到实战应用

本文详细介绍了如何使用Meta推出的Segment Anything Model(SAM)实现精准图像分割,从环境配置到实战应用的全流程。特别针对电商场景中的商品分割需求,提供了硬件配置、模型下载、API使用及优化策略等实用指南,帮助开发者快速掌握这一强大的深度学习工具。

pepsi的博客 1067

跟我一起读postgresql源码(四)——Planer(查询规划模块)(上)

http://www.cnblogs.com/flying-tiger/p/6063709.html 时间一晃周末就过完了,时间过得太快,不由得让人倍加珍惜。时间真是不够用哈~ 好的不废话,这次我们开始看查询规划模块的源码吧。 查询规划部分的在整个查询处理模块应该是在一个非常重要的地位上,这一步直接决定了查询的方式与路径,很大程度上影响了数据库查询的查询性能。因此这一块代

zdy0_2004的专栏 974

【数据集】30 m地表温度LST数据集

【数据集】30 m地表温度LST数据集

WW、forever的博客 1131

深入理解PostgreSQL Planner:简化扫描路径与查询计划

本文基于PostgreSQL 16源码,聚焦于一个最简单的查询场景——单表顺序扫描,逐步拆解规划器如何为查询生成扫描路径,以及这些路径最终如何转化为执行计划。对理解PostgreSQL规划器来说,这是最好的起点。

搞定过:百亿级数据、万级QPS、零宕机、AI工业化。 357

手把手教你用ESP32-C3打造智能聊天机器人-立创实战派

本文将详细介绍如何利用立创ESP32-C3开发板,烧录小智AI程序,快速实现一个功能强大的聊天机器人。

举世誉之而不加劝,举世非之而不加沮,定乎内外之分,辩乎荣辱之境,斯已矣。 5543

2025华为OD机试真题最新题库 (B+C+D+E+2025A+2025B卷) + 在线OJ在线刷题使用(C++、Java、Python C语言 JS合集)(正在更新2025B卷,目前已收录710道)

2024年,华为目前已经启用D卷,目前D卷和C卷的题目一样一次订阅永久阅读,支持在线刷题,持续更新,有问题随时解答,本专栏题目数量已收录到484道。每篇文章的思路分析都非常详细,题目新增图解思路,问题解疑,多样例测试,超过百字的思路参考解析。

KJ.JK 11万+

从Prompt到生产级Agent:构建健壮AI应用的架构与工程实践

Prompt工程是与大语言模型交互的基础技术,通过精心设计的指令、上下文和输出格式,引导模型生成符合预期的结果。其原理在于利用模型的上下文学习能力,将任务描述和示例嵌入输入中。然而,单纯依赖Prompt存在长度限制、静态性和无法调用外部工具等局限。为了突破这些限制,Agent(智能体)技术应运而生,它通过封装规划、工具使用和记忆等核心组件,赋予模型自主感知、决策和执行的能力,从而处理多步骤推理和复杂状态任务。在工程实践中,构建生产级Agent应用的核心价值在于实现服务的可靠性、可观测性和安全性,这需要将传统

weixin_30470643的博客 399

全志T527-TP9930-Camera

TP9930 驱动模块主要实现将 4 路的 AHD/TVI/CVBS Camera 的数据转换为 BT656/BT1120 数据,从而实现在 T527 端来对数据进行处理和送显。

Linux驱动开发工程师,熟悉Linux/Android底层驱动、TP、显示、IIC、网络等通用外设调试适配,Linux上层应用开发。常用平台瑞芯微、全志、恩智浦等。 3238

AI编程助手系统化增强:从碎片化对话到项目级智能协作

在软件开发领域,AI编程助手已成为提升效率的重要工具,但其在复杂项目中的碎片化响应和缺乏上下文记忆的问题限制了其潜力。通过引入上下文持久化、向量检索和动态语义理解等技术原理,可以实现AI助手对项目结构、编码规范和决策历史的持续记忆。这种系统化增强的核心技术价值在于将AI从孤立的代码生成器转变为理解项目全貌的智能协作者,显著降低开发者的认知负荷和上下文切换成本。在实际应用场景中,该方案尤其适用于需要长期维护的复杂项目、团队统一编码规范以及新成员快速融入等场景。本文探讨的everything-claude-co

weixin_34037515的博客 334

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

AI科研智能体:从论文解析到实验复现的自动化实践

大型语言模型(LLM)与智能体(Agent)技术的结合,正推动人工智能从内容生成迈向复杂任务规划与执行的新阶段。其核心原理在于,通过赋予AI理解多模态信息、调用工具链和进行多步推理的能力,使其能够模拟人类处理复杂问题的流程。这一技术价值在于,它有望将人类从重复性、流程化的认知劳动中解放出来,提升科研与工程实践的效率与规模。在应用场景上,AI智能体已开始渗透到自动化代码生成、数据分析、以及前沿的科学研究辅助等领域。本文聚焦于一个具体而前沿的应用——训练AI智能体复现科学研究,探讨如何构建一个能够理解论文、规划

weixin_30780649的博客 423

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

【PostgreSQL内核学习(四)—— 查询规划】

查询规划是数据库管理系统中的关键步骤之一,它涉及将用户提交的查询语句转换为可执行的执行计划。查询规划的目标是找到最优的执行计划,以在数据库中高效地执行查询操作。该过程包括查询优化、索引选择、连接顺序、访问方法等决策,以及生成最终的查询执行计划,以便在数据库系统中执行查询并返回结果。

qq_43899283的博客 1316

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

《PG源码学习--4.查询规划》

查询经过语法解析,语义分析,规则重写,到了查询计划环节。这里学习查询计划的代码。 一.入口 postgres\src\backend\optimizer\plan\planer.c PlannedStmt * planner(Query *parse, int cursorOptions, ParamListInfo boundParams) { PlannedStmt *result; ...

weixin_39939108的博客 894

PostgreSQL源码分析——执行计划EXPLAIN

在Postgres中,显示执行计划可用explain命令,示例如下: 我们分析一下源码,看一下 是怎么显示执行计划的,选取了一条简单的查询语句。如果是数据库内核开发者,在新实现某个算子或者新增了某个Plan,这时还需要改一下执行计划显示相关代码,主要在explain.c中。我们分析一下其大概的过程。输入这条语句 进行分析。在进行源码跟踪前想一下,如果自己实现,应该怎么做呢?大概步骤如下:后面我们跟踪一下源码,看源码是怎么实现的。主要代码在 中。我们看一下其执行流程 EXPLAIN语法定义 在gram.y中定

内核思考 2492

postgresql源码分析

包含列数量、类型、名称等信息用于解析和构造元组。

Made In SQL 1253

【PostgreSQL内核学习(五)—— 查询规划(预处理)】

预处理的主要工作是提升子链接和子查询以及预处理表达式和HAVING子句等。预处理部分主要是对查询树Query中的范围表rtable和连接树jointree等进行处理。

qq_43899283的博客 833

PostgreSQL查询优化器源码分析--整体流程

函数间关系的主要逻辑如下: planner(){――第(1)层   standard_planner(){――第(2)层  subquery_planner(){――第(3)层   pull_up_sublinks(); //上拉子链接 pull_up_subqueries(); //上拉子查询 preprocess_expression(); //标准化表达式:把WHERE子句内容

那海蓝蓝的博客 918
上一篇: IvorySQL 增量备份与合并增量备份功能解析
下一篇: 在 PostgreSQL 中设置调试环境以更好地理解 OpenSSL API
IvorySQL
博客等级 码龄5年 745粉丝 565原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值