当前位置: 首页 > news >正文

DeepSeek总结的PostgreSQL 19查询提示功能

来源:https://thebuild.com/blog/2026/04/21/hints-part-3-advice-not-orders/

提示,第三部分:建议,而非命令

我对pg_plan_advice早期预览版的反应。

Robert Haas 的pg_plan_advice补丁集(提议用于 PostgreSQL 19)是第二部分中那场持续了二十年的争论所达成的(或者说试图达成的)结果。它不是将pg_hint_plan引入核心。它是一个不同的东西,具有不同的机制、不同的范围,并且对“这与 Oracle 风格的提示有何不同”这个问题给出了不同的答案。

该补丁引入了三个contrib模块:

  • pg_plan_advice—— 核心机制。通过EXPLAIN生成计划建议字符串,并通过一个 GUC 来应用它们。
  • pg_collect_advice—— 一个示例扩展,展示了如何扩展建议收集功能。
  • pg_stash_advice—— 一个示例扩展,展示了如何扩展建议应用功能,通过查询标识符将存储的建议字符串与查询匹配。

这种三部分拆分很重要。pg_plan_advice被刻意设计得极简——Haas 将这种设计描述为“机制,而非策略”——而另外两个模块则演示了你可以在此基础上构建什么。该架构假设其他扩展将完成有趣的工作。

生成建议

加载扩展并使用新的PLAN_ADVICE选项运行EXPLAIN

LOAD'pg_plan_advice';EXPLAIN(COSTSOFF,PLAN_ADVICE)SELECT*FROMjoin_fact fJOINjoin_dim dONf.dim_id=d.id;
QUERY PLAN ------------------------------------ Hash Join Hash Cond: (f.dim_id = d.id) -> Seq Scan on join_fact f -> Hash -> Seq Scan on join_dim d Generated Plan Advice: JOIN_ORDER(f d) HASH_JOIN(d) SEQ_SCAN(f d) NO_GATHER(f d)

“Generated Plan Advice” 部分就是新的输出。它以一种紧凑、结构化的形式描述了计划形态:连接顺序、连接方法、每个表的扫描方法、并行决策。这就是建议字符串。

应用建议

通过一个 GUC 将建议交还给规划器:

BEGIN;SETLOCALpg_plan_advice.advice='HASH_JOIN(d)';EXPLAIN(COSTSOFF,PLAN_ADVICE)SELECT*FROMjoin_fact fJOINjoin_dim dONf.dim_id=d.id;

规划器产生相同的哈希连接计划,并且EXPLAIN输出现在在生成的建议旁边包含一个“Supplied Plan Advice”部分,用/* matched */或未匹配注释每个提供的指令。你可以准确地看到规划器采纳了你的哪些建议。

你不必传回完整的建议字符串。只关心你关心的部分也可以。如果你只想固定连接方法,而让规划器决定其他一切,只需传递HASH_JOIN(d)

强制不同的计划

改变建议字符串以强制不同的计划形态:

SETLOCALpg_plan_advice.advice='MERGE_JOIN_PLAIN(d)';EXPLAIN(COSTSOFF,PLAN_ADVICE)SELECT*FROMjoin_fact fJOINjoin_dim dONf.dim_id=d.id;
QUERY PLAN ---------------------------------------------------------------- Merge Join Merge Cond: (f.dim_id = d.id) -> Index Scan using join_fact_dim_id on join_fact f -> Index Scan using join_dim_pkey on join_dim d Supplied Plan Advice: MERGE_JOIN_PLAIN(d) /* matched */ Generated Plan Advice: JOIN_ORDER(f d) MERGE_JOIN_PLAIN(d) INDEX_SCAN(f public.join_fact_dim_id d public.join_dim_pkey) NO_GATHER(f d)

注意生成的建议是如何更新以反映新计划的。改变连接方法,扫描方法也随之改变——规划器现在选择索引扫描以为合并连接提供排序输入。建议机制强制执行你指定的选择,而规划器仍然围绕这些选择优化其他所有内容。

建议词汇表

从回归测试和 Haas 的博客文章来看,当前的指令包括:

  • JOIN_ORDER(rel1 rel2 ...)—— 命名关系的连接顺序
  • HASH_JOIN(rel),MERGE_JOIN_PLAIN(rel)—— 给定关系的连接方法
  • SEQ_SCAN(rel),INDEX_SCAN(rel idx ...)—— 扫描方法,带有可选的索引规范
  • NO_GATHER(rel rel ...)—— 禁用命名关系的并行 gather

这比 Oracle 或pg_hint_plan支持的范围要窄。明显缺失的包括:基数覆盖、行数注入、规划器成本覆盖、返回集合函数的提示、物化指令。其表面积是故意做小的。这是 1.0 版本,Haas 对此很坦诚——“有很多限制”和“一些仍然相当笨拙的东西”。预计词汇表会增长。

pg_stash_advice:不触碰查询的建议

为每个查询设置一个 GUC 对于交互式调试来说没问题,但对于生产环境来说毫无用处。这就是pg_stash_advice的用途:

ALTERSYSTEMSETshared_preload_libraries='pg_stash_advice';ALTERSYSTEMSETpg_stash_advice.stash_name='my_stash';SELECTpg_create_advice_stash('my_stash');SELECTpg_set_stashed_advice('my_stash',:qid,'MERGE_JOIN_PLAIN(d)');

重新加载后,每次在pg_stash_advice.stash_name匹配的会话中规划具有该查询标识符的查询时,存储的建议都会自动应用。你没有触碰 SQL。你没有触碰应用程序。你从一个具有适当权限的数据库角色固定了计划。

这是 SQL Server 的计划指南模式和 Db2 的优化配置文件模式,在它们出现近二十年后才落地 PostgreSQL。

存储库通过查询标识符来键——就是你在pg_stat_statements中看到的那个标识符。因此工作流程自然形成:通过pg_stat_statements找到一个慢查询,通过EXPLAIN (PLAN_ADVICE)为你想要的计划获取建议,将其存储到查询 id 下,然后就不用管了。

如果pg_plan_advice.advice和存储的建议条目同时适用于一个查询,则会话级别的设置获胜。存储的建议是基线;会话设置是覆盖。

机制,而非策略

Haas 对该架构的表述很明确:pg_plan_advice是可插拔的核心,而pg_stash_advicepg_collect_advice是演示可插拔性让你能构建什么的示例扩展。pg_stash_advice通过查询标识符键并在动态共享内存中存储,这是一个合理的默认值,并不是因为它唯一正确的设计。一个不同的扩展可以通过你计算的查询哈希、通过规范化查询文本的正则表达式、通过用户或角色、通过任何方式来键。一个不同的扩展可以将建议存储在目录表、etcd、sidecar 服务中。

这就是为什么pg_plan_advice不是将pg_hint_plan引入核心。pg_hint_plan是一个完整的、有主见的解决方案。pg_plan_advice是一个工具包。

实际的结果是,一旦这个落地,pg_hint_plan本身就可以减少大量的代码。它目前为了实现其功能而复制了规划器的大部分内容;新的基础设施可以让大部分重复代码消失。pg_hint_plan将成为pg_plan_advice钩子的消费者,而不是规划器的并行实现。无论你对提示这一概念持何种看法,这都是一个真正的工程学胜利。

这如何回答(或不回答)六个反对理由

回顾一下第二部分的列表:

  1. 可维护性。pg_stash_advice将建议键与查询标识符关联,而不是嵌入在 SQL 中。你在数据库中更改建议,而不是在应用程序中。已回答。
  2. 升级干扰。部分回答。如果你只存储你关心的特定指令——例如MERGE_JOIN_PLAIN(d),没有别的——规划器会继续自适应地优化其他所有内容。一个完整的、逐字固定的建议字符串会重新引入这个问题。该工具允许克制使用;它不强制执行。
  3. 助长 DBA 的坏习惯。未回答,也无意回答。一个求助于pg_plan_advice而不是修复统计信息问题的 DBA 将会得到与使用pg_hint_plan相同的糟糕结果。这是一个文化问题,而不是技术问题。
  4. 不随数据规模扩展。部分回答,原因与升级相同。有针对性的建议比完全固定计划更能承受数据增长。完全固定计划有其一直以来的问题。
  5. 通常是不必要的。无关。这个反对意见从来就不是关于机制应该是什么样子,而只是关于机制是否应该存在。pg_plan_advice承认它有时是必要的。
  6. 干扰规划器开发。原始反对意见中最薄弱的一个,现在更弱了。pg_stat_statements加上pg_plan_advice使得描述和报告规划器衰退变得微不足道。存储的建议是证据,而不是掩饰。

状态

该补丁尚未提交。Haas 指出“将功能纳入 v19 的时间正在迅速耗尽”,并且 -hackers 的讨论一直很热烈——既有支持也有怀疑。Andrey 在博客评论中指出,pg_hint_plan已经解决了这个问题,并且不应为了服务一个扩展已经处理的用例而使核心规划器复杂化。这不是一个边缘的反对意见。这是对 2011 年立场的合理重述,针对 2026 年进行了重申。

无论pg_plan_advice是落地于 19、20 还是永远不会落地,争论已经发生了变化。核心项目不再说“我们不想要这个”。它正在就具体形态进行协商。

这才是真正的新闻。

http://www.cnnetsun.cn/news/2033330.html

相关文章:

  • Unity网络通信避坑指南:从原生Socket到Mirror,我的多人聊天室开发踩坑实录
  • PKHeX自动合法性插件:新手5分钟快速上手宝可梦数据合规指南
  • ADAPT-VQE算法与格点规范理论的量子计算应用
  • 用Qt 5.14.2 + EMQX搭建本地物联网消息测试环境:从客户端到服务器一条龙配置
  • 终极二维码修复指南:使用QrazyBox拯救损坏的QR码
  • 5步掌握Navicat重置工具:macOS平台终极免费解决方案
  • 深入解析TrollInstallerX架构:从内核漏洞利用到iOS应用持久化的完整技术指南
  • 企业级托管钱包架构设计与MPC密钥管理:基于Go语言的生产级实践
  • GPU加速CFD求解器的异构计算优化策略
  • 【独家首发】LSTM预测模型验证的Docker资源配置最优解:基于27家金融机构生产负载的CPU/Mem/IO弹性配比公式
  • Python实战:鲁棒回归算法解析与工程应用
  • UE4开发避坑:手把手教你搞定PS4和Switch Pro手柄的Raw Input插件配置
  • 告别记事本!用GVim打造你的Windows专属代码编辑器(附详细_vimrc配置与插件推荐)
  • Qwen3.5-4B模型VMware虚拟机Ubuntu开发环境一站式配置
  • GitOps 实战:ArgoCD 在生产环境的多集群部署与管理
  • 我帮业主验过百套硬装,总结一套可直接照抄的标准
  • Qwen3-4B-Thinking创意写作效果:小说大纲+人物关系链+伏笔设计
  • Blazor 2026开发环境强制升级倒计时:.NET 9 SDK将在2026年4月1日终止对<9.0.200版本的NuGet签名验证(立即执行迁移检查清单)
  • 3分钟掌握B站视频缓存转换:让离线视频真正属于你
  • Qwen3.5-9B-GGUF开源大模型部署:Apache 2.0协议下商用微调全流程解析
  • 告别STM32开发板!手把手教你用Vivado在Zynq FPGA上“复刻”一个Cortex-M3软核
  • 5个核心机制深度剖析:Seraphine如何将LCU API转化为你的英雄联盟智能助手
  • WebToEpub:一键将网页小说转换为EPUB电子书的终极方案
  • 从F-22到你的手机:拆解‘有源相控阵’技术,看它如何悄悄改变我们的生活
  • 实测分享:用速腾RS-Helios-16P和百元级IMU跑通Fast-LIO2,低成本SLAM方案可行吗?
  • 不用C盘!MaixPy3开发环境最佳实践:自定义安装路径+多版本管理技巧
  • 知乎API库:Python开发者的社交数据采集利器
  • 技能集体演化:SkillClaw如何让多用户Agent系统“越用越强“
  • Elasticsearch磁盘被java_pid*.hprof文件塞满?别慌,5分钟教你定位并清理内存溢出垃圾
  • 别再让Unity微信小游戏里的中文变‘口口’了!手把手教你用Custom Set搞定字体(附自动扫描脚本)