Klavis 仓库 Postgres MCP 服务器的 Explain Plan 工具:深入解析 PostgreSQL 查询执行计划分析能力

发布时间:2026/9/17 20:19:22
Klavis 仓库 Postgres MCP 服务器的 Explain Plan 工具:深入解析 PostgreSQL 查询执行计划分析能力
Klavis 仓库 Postgres MCP 服务器的 Explain Plan 工具深入解析 PostgreSQL 查询执行计划分析能力【免费下载链接】klavisKlavis AI: MCP integration platforms that let AI agents use tools reliably at any scale项目地址: https://gitcode.com/GitHub_Trending/kl/klavis本文以仓库mcp_servers/postgres/src/postgres_mcp/explain/模块为核心系统讲解其提供的explain_queryMCP 工具从基本 EXPLAIN、EXPLAIN ANALYZE 到基于 HypoPG 的假设索引模拟并深入到绑定变量替换、PostgreSQL 版本兼容处理与执行计划结果结构化解析的源码实现帮助你在开发与生产环境中把 AI Agent 变成一位可靠的查询性能分析助手。模块概览为 AI Agent 打造的执行计划分析层PostgreSQL 的EXPLAIN命令是查询性能调优的基石但它输出的是面向数据库专家的文本。Klavis 仓库中的 Postgres MCP 服务器在 explain/README.md 中定义了一个专门的分析模块其定位非常明确为 AI Agent 提供生成与分析 PostgreSQL 查询执行计划query execution plan的工具。该模块由以下三个文件构成文件职责explain_plan.pyExplainPlanTool核心类负责构建 EXPLAIN 语句、处理绑定变量、执行假设索引模拟init.py模块出口导出ExplainPlanToolREADME.md模块文档即本文依据模块提供的核心能力被封装为 MCP 服务器上的explain_query工具定义于 server.py。围绕这一工具模块实现了三类价值查询理解Query Understanding揭示 PostgreSQL 将如何执行某条查询包括访问路径、连接顺序与成本估算性能分析Performance Analysis借助真实执行统计ANALYZE定位瓶颈与优化机会索引测试Index Testing在不真实创建索引的前提下用假设索引hypothetical index验证加了某个索引后查询会变多快。explain_query 工具参数与调用方式explain_query是 Agent 通过 MCP API 与数据库交互的入口。其 JSON Schema 定义在 server.py参数如下参数类型必填默认值说明sqlstring是—需要分析执行计划的 SQL 查询analyzeboolean否false为true时真正执行查询返回真实执行统计而非成本估算hypothetical_indexesarray否[]需要模拟的假设索引列表不实际创建索引调用时服务端会按照以下优先级分派见 explain_query_tool若提供了hypothetical_indexes检查 HypoPG 扩展是否安装随后走explain_with_hypothetical_indexes路径若同时传入analyzetrue会直接报错Cannot use analyze and hypothetical indexes together因为 HypoPG 的假设索引无法真实执行否则若analyzetrue走explain_analyze即EXPLAIN (FORMAT JSON, ANALYZE)否则走普通explain即EXPLAIN (FORMAT JSON)。一个典型的调用序列大致是{ name: explain_query, arguments: { sql: SELECT * FROM orders WHERE customer_id 42 AND created_at 2023-01-01, analyze: false } }而模拟索引的调用则形如{ name: explain_query, arguments: { sql: SELECT * FROM orders WHERE customer_id 42, hypothetical_indexes: [ { table: orders, columns: [customer_id] }, { table: orders, columns: [customer_id, created_at], using: btree } ] } }三种 EXPLAIN 模式的底层 SQL 构造ExplainPlanTool内部通过_run_explain_query组装 EXPLAIN 语句explain_plan.pyexplain_options [FORMAT JSON] if analyze: explain_options.append(ANALYZE) if generic_plan: explain_options.append(GENERIC_PLAN) explain_q fEXPLAIN ({, .join(explain_options)}) {query} rows await self.sql_driver.execute_query(explain_q)也就是说三种模式分别对应基本 EXPLAINEXPLAIN (FORMAT JSON) SELECT ...EXPLAIN ANALYZEEXPLAIN (FORMAT JSON, ANALYZE) SELECT ...通用计划PostgreSQL ≥ 16EXPLAIN (FORMAT JSON, GENERIC_PLAN) SELECT ...执行结果统一取QUERY PLAN单元格并以 JSON 格式解析——这保证了后续无论走哪条路径得到的都是结构化、可程序化消费的计划数据。单元测试 test_explain_plan.py 验证了EXPLAIN (FORMAT JSON) SELECT * FROM users这一组装结果。绑定变量处理让 EXPLAIN 拿到真实的参数值真实业务中的查询往往带有绑定变量如WHERE id $1。直接对这些 SQL 执行 EXPLAIN 会得到不准确的计划因为优化器缺少关键参数值。ExplainPlanTool在 replace_query_parameters_if_needed 中实现了完整的决策逻辑检测到绑定变量 ($1, $2, ...) ├── 查询是否含 LIKE 表达式→ 是 → 参数替换LIKE 与 GENERIC_PLAN 不兼容 ├── PostgreSQL 版本 ≥ 16→ 是 → 使用 GENERIC_PLAN保留 $1 占位符 └── PostgreSQL 版本 16→ 是 → 参数替换GENERIC_PLAN 与版本门槛PostgreSQL 16 引入了EXPLAIN (GENERIC_PLAN)允许在不知道参数具体值的情况下生成通用执行计划。代码通过check_postgres_version_requirement(sql_driver, min_version16, feature_nameGeneric plan with bind variables ($1, $2, etc.))检测版本该函数实现在 extension_utils.py底层通过SHOW server_version获取主版本号并做全局缓存。当 PostgreSQL 16 或查询含 LIKE 表达式时则退化为参数替换策略。测试 test_explain_plan.py 验证了 PG 16 下EXPLAIN (FORMAT JSON, GENERIC_PLAN) SELECT * FROM users WHERE id $1的生成而 L136-L200 则验证了 PG 15 下参数被替换为示例值且不出现GENERIC_PLAN关键字。基于列统计的参数替换SqlBindParams当需要参数替换时模块调用 bind_params.py 中的SqlBindParams.replace_parameters。这套实现远比随便填个值复杂特殊子句优先处理LIMIT替换为100、OFFSET替换为0、INTERVAL $1替换为interval 2 daysBETWEEN 双参数结合pg_stats中的most_common_vals/histogram_bounds生成贴合数据分布的上界与下界逐参数识别所属列先用pglastlibpg_query 的 Python 封装对 SQL 做 AST 解析parse_sql通过TableAliasVisitor/ColumnCollector等 Visitor 提取表别名与列引用再结合上下文column $1、column $1、column LIKE $1等模式判定参数归属按列统计类型取值字符串列取最常见值、LIKE场景取%test%、数值列取直方图中值、日期列取2023-01-01等全部数据来自pg_stats视图并带内存缓存兜底策略统计信息缺失时依据列名语义*_id用 46、price用 99.99、status用active等做上下文猜测。这一层保证了 EXPLAIN 得到的计划尽量贴近真实参数下的执行路径是让 Agent 的调优建议靠谱的关键前置工作。假设索引用 HypoPG 做到先验证、后建索引hypothetical_indexes是explain_query最有价值的参数。它基于 HypoPG 扩展hypopg实现——该扩展创建虚拟索引让优化器在生成计划时把这些索引纳入考虑但数据库里并不真的创建它们因此零存储成本、零写入放大、可随时清空。索引定义校验与规范化在 explain_with_hypothetical_indexes 中模块先对入参做严格校验必须是列表否则返回ErrorResult每个元素必须是字典且必须包含table与columns字段columns会被强制转换为列表支持传单个字符串可选using字段指定索引方法默认btree。校验通过后索引定义被转换为不可变的IndexDefinitionsql/index.py其definition属性生成形如CREATE INDEX crystaldba_idx_{table}_{columns} ON {table} USING {using} ({columns})的语句。值得注意的实现细节是索引命名会清洗函数表达式——例如LOWER(primary_title)会被清洗为LOWER_primary_title_从而支持函数索引functional index的模拟。一次调用背后的完整 SQL 序列generate_explain_plan_with_hypothetical_indexesexplain_plan.py把多个语句拼接成一次执行SELECT hypopg_reset(); -- 1. 清空上次的假设索引 SELECT hypopg_create_index(CREATE INDEX ...); -- 2. 为每个索引创建虚拟索引 EXPLAIN (FORMAT JSON, COSTS TRUE) query -- 3. 生成包含假设索引的执行计划hypopg_reset()保证每次调用从干净状态开始hypopg_create_index()接收完整的CREATE INDEX语句文本通过SafeSqlDriver.param_sql_to_query做参数化拼接防止注入附加COSTS TRUE确保成本信息完整输出便于后续量化收益若执行失败或结果为空返回{Plan: {Total Cost: float(inf)}}用无穷大成本标记不可行方案——这个约定在索引调优模块中被当作该索引无效的信号。单元测试 test_explain_plan.py 完整验证了包含LOWER(primary_title)、start_year DESC等复杂表达式索引的 SQL 拼接结果。HypoPG 未安装时的引导式提示由于 HypoPG 不一定随 PostgreSQL 发行服务端在调用前会执行check_hypopg_installation_statusextension_utils.py返回三段式状态已安装直接放行可用未安装提示 Agent 可通过execute_query工具执行CREATE EXTENSION hypopg;并说明安全性虚拟层、不真实创建索引、撤销方式DROP EXTENSION hypopg;系统未提供给出按发行版安装的指引如 Debian/Ubuntu 的apt-get install postgresql-{version}-hypopg并要求随后CREATE EXTENSION hypopg;。这种诊断 可执行的下一步指引设计让 AI Agent 在缺少依赖时也能自主推进而不是直接报错终止。结果处理从 JSON 计划到可读文本EXPLAIN 的FORMAT JSON输出是嵌套的字典结构。模块通过 artifacts.py 中的ExplainPlanArtifact与PlanNode两个类完成结构化解析与展示。PlanNode计划树的统一抽象PlanNode.from_json_dataartifacts.py递归地把 JSON 计划树映射为对象模型提取字段包括基础成本模型Node Type、Startup Cost、Total Cost、Plan Rows、Plan WidthANALYZE 真实指标Actual Total Time、Actual Startup Time、Actual Rows、Actual Loops缓冲区信息Shared Hit Blocks、Shared Read Blocks、Shared Written Blocks关系名与过滤条件Relation Name、Filter子计划Plans数组递归生成children。文本渲染与计划对比ExplainPlanArtifact.to_text把计划树渲染为带缩进的文本树形如→ Seq Scan on users (Cost: 0.00..10.00) [Rows: 100]若包含 ANALYZE 真实指标则追加[Actual: 0.01..1.23 ms, Rows: 95, Loops: 1]缓冲区信息与过滤条件超过 100 字符自动截断也会附上同时输出Planning Time/Execution Time。create_plan_diffartifacts.py更进一步它对比加索引前与加索引后两份计划生成结构化 diff包含成本变化Cost: 100.00 → 10.00 (10.0x improvement)、节点类型变化、顺序扫描被替换的数量、新增索引扫描的数量等。这一能力正是仓库中索引调优模块analyze_workload_indexes/analyze_query_indexes向 Agent 汇报优化收益的文字基础也让explain_query本身就可以作为独立的假设索引验证器使用。集成位置与适用前提explain_query只是 Postgres MCP 服务器九个工具之一其余工具包括list_schemas、list_objects、get_object_details、execute_sql、get_top_queries、analyze_workload_indexes、analyze_query_indexes、analyze_db_health完整注册见 server.py。在典型工作流中Agent 可先用get_top_queries找出慢查询再用explain_query分析瓶颈、用hypothetical_indexes验证索引方案最后通过analyze_query_indexes获得完整调优建议。使用前需要注意以下适用前提以仓库实际实现为准PostgreSQL 版本项目测试主要覆盖 PG 15/16/17见 postgres/README.md FAQGENERIC_PLAN绑定变量路径要求 PG ≥ 16更早版本自动走参数替换扩展依赖hypothetical_indexes依赖hypopg扩展get_top_queries依赖pg_stat_statements访问模式服务器以--access-moderestricted启动时使用只读的SafeSqlDriverexplain_query的只读语义天然兼容受限模式工具标注了readOnlyHint数据分布参数替换的准确性依赖pg_stats统计信息建议在数据库执行过ANALYZE/ 启用了 autovacuum 的情况下使用。源码速查想要深入阅读本模块可按以下路径展开模块文档explain/README.md核心实现explain/explain_plan.py计划解析与渲染artifacts.py参数替换实现sql/bind_params.py扩展检测与版本检查sql/extension_utils.py索引定义模型sql/index.pyMCP 工具注册与分派server.py单元测试tests/unit/explain/test_explain_plan.py、tests/unit/explain/test_server.py真实数据库集成测试tests/unit/explain/test_explain_plan_real_db.py总而言之Postgres MCP 服务器的 Explain 模块把 PostgreSQL 原生的 EXPLAIN 能力封装成了对 Agent 友好、结果结构化、且支持零成本索引试验的 MCP 工具。无论是排查慢查询、验证新索引方案还是把执行计划交给 LLM 做进一步的调优推理explain_query都是一个可以直接信赖的底层构件。【免费下载链接】klavisKlavis AI: MCP integration platforms that let AI agents use tools reliably at any scale项目地址: https://gitcode.com/GitHub_Trending/kl/klavis创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考