Gel CLI 查询性能分析完全指南:掌握 `gel analyze` 命令、输出解读与 JSON 工作流
2026/9/23 2:59:23 网站建设 项目流程
  • 数据库
  • 图数据库
  • 关系型数据库

【免费下载链接】edgedb

Gel supercharges Postgres with a modern data model, graph queries, Auth & AI solutions, and much more.

项目地址:https://gitcode.com/gh_mirrors/ed/edgedb
点击查看免费下载

gel analyze是 Gel 官方 CLI 中用于对 EdgeQL 查询执行性能分析的核心命令。它直接作用于当前连接的实例,为查询生成 PostgreSQL 底层执行计划视图,帮助开发者定位慢查询的瓶颈所在。读完本文,你将掌握gel analyze的完整语法与全部选项、如何解读粗粒度与展开后的细粒度性能指标,以及如何借助 JSON 文件实现分析与渲染解耦的自动化工作流。

概述:一条命令,三个入口

Gel 的查询性能分析能力并不仅限于 CLI 命令本身,整个生态提供了三种等价的使用入口,gel analyze是其中最直接、最适合脚本化与离线分析的一种:

  1. CLI 命令gel analyze <query>,即本文主角,适合在终端中一次性完成分析;
  2. CLI REPL:在gel交互式 shell 中,可以直接在查询前加analyze前缀,或使用\analyze QUERY反斜杠命令;分析完成后还能用\expand打印上一次分析的展开(细粒度)输出,详见 docs/reference/using/cli/gel.rst;
  3. UI 的 REPL 与查询构建器(Query Builder):通过运行gel ui唤起实例的 Web UI,在查询编辑器中将analyze前缀加到查询前即可获得可视化性能分析;UI 内置的视觉化查询分析器自 3.0 起引入,可帮助直观调整 EdgeQL 查询性能(见 docs/resources/changelog/3_x.rst)。

EdgeQL 语句层面的语法参考位于 docs/reference/edgeql/analyze.rst 与 docs/reference/reference/edgeql/analyze.rst。

命令语法与全部选项

gel analyze的命令行语法为:

gel analyze [<options>] <query>

该命令运行在**当前连接的数据库(branch)**上,因此连接目标的指定方式与其余 Gel CLI 命令完全一致(详见下文「连接目标」小节)。

选项说明
<query>待分析的查询。务必用引号包裹整个查询,防止 shell 对其中特殊字符(如花括号、分号)做错误解释。
--expand打印查询分析的展开输出,即比默认粗粒度计划更细粒度的性能指标。
--debug-output-file <debug_output_file>将分析结果以 JSON 格式写入指定文件,而非进行格式化输出。
--read-json <read_json>读取已保存的 JSON 文件进行分析展示,而不实际执行查询。

其中--debug-output-file--read-json组合,形成了一条典型的「先分析落盘、后离线渲染」的工作流:先在服务器端执行一次analyze并把原始 JSON 保存下来,之后无论是否还能连接数据库,都可以随时用--read-json重新查看该分析结果,非常适合性能回归对比与团队间共享分析产物。

一个最小可用示例

# 直接分析一条查询(注意引号) gel analyze "select Hero {name, secret_identity, villains: {name, nemesis: {name}}}" # 将分析结果保存为 JSON,供后续离线查看 gel analyze --debug-output-file plan.json "select Hero {name}" # 不执行查询,直接渲染先前保存的 JSON 分析 gel analyze --read-json plan.json # 查看细粒度展开输出 gel analyze --expand "select Hero {name}"

解读默认输出:粗粒度查询计划

对一条简单查询执行gel analyze后,终端会得到如下输出(示例来自原文档 docs/reference/using/cli/gel_analyze.rst,测试配套 Schema 位于 tests/schemas/explain.esdl):

──────────────────────────────────────── Query ──────────────────────────────────────── analyze select ➊ Hero {name, secret_identity, ➋ villains: {name, ➌ nemesis: {name}}}; ──────────────────────── Coarse-grained Query Plan ──────────────────────── │ Time Cost Loops Rows Width │ Relations ➊ root │ 0.0 69709.48 1.0 0.0 32 │ Hero ╰──➋ .villains │ 0.0 92.9 0.0 0.0 32 │ Villain, Hero.villains ╰──➌ .nemesis │ 0.0 8.18 0.0 0.0 32 │ Hero

输出分为两个区块:

  • Query 区块:回显被分析的 EdgeQL 查询原文,并用编号圆点(➊➋➌)将查询中每个关键形状(shape)节点与下方的计划行一一对应,便于把 SQL 层面的成本映射回 EdgeQL 语法结构;
  • Coarse-grained Query Plan(粗粒度查询计划)区块:以树形结构展示查询各部分的执行代价。其中每一列含义如下:
含义
Time该节点预估的执行时间(毫秒级浮点值,示例中均为0.0,表示耗时极小)
CostPostgreSQL 规划器给出的相对成本估算值,成本越大意味着越昂贵(示例中root69709.48远高于其余节点,是性能关注重点)
Loops该节点预估被循环执行的次数(示例中root1.0,而嵌套链路节点为0.0,表示位于更深的循环体中)
Rows预估输出的行数
Width预估每行的平均字节宽度
Relations该节点涉及的实际 PostgreSQL 关系(表/视图),例如HeroVillain, Hero.villains

树形缩进(╰──)清晰展示了查询形状的嵌套关系:root对应Hero的顶层查询;其下.villains对应 villains 链接的展开,涉及Villain表与Hero.villains关联表;再下层.nemesis对应嵌套的 nemesis 展开。据此可以快速判断哪一层形状的展开引入了最大的成本,从而决定是否裁剪查询形状、增加索引或改写链接结构。

展开输出:从粗粒度到细粒度

默认的粗粒度计划聚焦「查询形状 → 关系」的映射,便于快速定位问题层级;而--expand(以及在 REPL 中对上一次analyze执行\expand)则输出**细粒度(fine-grained)**的计划,展示 PostgreSQL 规划器为每个形状节点生成的具体执行节点(如顺序扫描、索引扫描、哈希连接、聚合等),以及更精确的代价估算。

从测试代码 tests/test_edgeql_explain.py 可以确认这两种输出在内部是同时生成的,且以结构化字段形式存在:测试断言res['fine_grained'](细粒度)与res['coarse_grained'](粗粒度)均为非空对象,例如test_edgeql_explain_bug_5758test_edgeql_explain_bug_5791两个用例专门验证了复杂嵌套查询下粗粒度计划不会因找不到主别名而缺失(tests/test_edgeql_explain.py#L2005、tests/test_edgeql_explain.py#L2094)。

细粒度 JSON 的核心结构包含:

  • contexts:将查询原文中的位置区间映射到计划节点的上下文信息;
  • pipeline:执行流水线中各计划节点的描述数组,每个节点含plan_type(如IndexScanBitmapHeapScanSeqScan等)、properties等字段;
  • 可选指标如shared_read_blocks(共享缓冲读取块数)。

测试用例test_edgeql_explain_simple_01即直接对select User { id, name } filter .name = 'Elvis'fine_grained结果断言了contexts的结构(tests/test_edgeql_explain.py#L90-L99)。当你在细粒度输出中看到plan_typeIndexScanBitmapHeapScan时,说明查询正确命中了索引;Gel 测试套件中的_assert_index_use辅助函数正是用这一模式来验证「查询确实使用了索引」(tests/test_edgeql_explain.py#L69-L88)。

使用场景建议

  • 查询变慢时,先用gel analyze的默认粗粒度输出确认瓶颈在哪个形状节点;
  • 再用--expand深入该节点,判断是扫描方式(SeqScan vs IndexScan)还是连接策略导致的高成本;
  • 若发现顺序扫描,可参考 docs/reference/datamodel/indexes.rst 为对应属性建立索引后重新分析对比。

JSON 工作流:--debug-output-file--read-json

在自动化场景中,终端表格输出并不利于程序消费,此时应使用--debug-output-file将分析结果以 JSON 落盘:

# 1. 执行分析并写入 JSON gel analyze --debug-output-file perf/hero_query.json \ "select Hero {name, secret_identity, villains: {name, nemesis: {name}}}" # 2. 之后任意时刻离线渲染该结果(无需连接实例) gel analyze --read-json perf/hero_query.json

这两条选项组合的实际意义在于执行与分析解耦:执行查询获取计划只需一次,而解读、分享、归档可以无限次进行;同时 JSON 原始数据是后续编写自动化性能断言、构建 CI 性能门槛的基础素材。从测试代码可见,Gel 服务端返回的analyze结果本质上就是可被json.loads解析的结构化对象(tests/test_edgeql_explain.py#L64-L67),因此--debug-output-file保存的正是与之一致的原始数据。

用参数微调分析行为

在 EdgeQL 语句层面,analyze还支持以命名元组形式传入分析参数,典型用法见测试用例(tests/test_edgeql_explain.py#L1318-L1347):

# 打开缓冲区统计(会输出 shared_read_blocks 等指标) analyze (buffers := True) select User; # 关闭缓冲区统计(默认行为) analyze (buffers := false) select User; # 不实际执行查询,仅生成计划 analyze (execute := False) select User; # 非法参数会报错 analyze (bogus_argument := True) select User;

(buffers := True)会在线程化查询中额外统计共享缓冲区读取块数(对应shared_read_blocks字段),适合排查磁盘 I/O 相关的性能问题;(execute := False)则跳过真实执行,仅获取规划器默认计划——Gel 测试套件在无真实数据的小数据集上也依赖该模式做计划结构断言。以上语法在 CLI REPL、UI REPL 中均可直接使用,是gel analyze命令行选项之外更细粒度的控制手段。

连接目标:analyze 作用于哪个实例

gel analyze与其他 Gel CLI 命令共用同一套连接参数解析体系,完整选项清单见 docs/reference/using/cli/gel_connopts.rst。连接目标的解析优先级如下:

  1. 显式命令行参数优先:如-I <name>/--instance=<name>(命名实例,Cloud 实例格式为<org-name>/<instance-name>)、--dsn=<dsn>--credentials-file-H/--host-P/--port(默认5656)、--unix-path--admin-u/--user-b/--branch等;
  2. 未显式指定时,读取对应环境变量(如GEL_HOSTGEL_PORTGEL_USERGEL_BRANCHGEL_DSN等);
  3. 仍缺失时,检查当前工作目录是否位于已链接实例的项目目录内(由gel project init建立);
  4. 以上均不满足则命令失败。

常用实践示例:

# 指定实例 gel analyze -I my_instance "select Hero {name}" # 指定 DSN gel analyze --dsn "gel://user:pass@localhost:5656/main" "select Hero {name}" # 指定分支(Gel 5.0 起数据库概念被分支取代) gel analyze -b analytics "select Hero {name}"

注意:Gel 5.0 之前分支被称为数据库,旧的-d/--databaseGEL_DATABASE环境变量仍被支持以保持向后兼容。

源码视角:analyze 语句如何被解析与执行

从语法层看,analyze是 EdgeQL 语法中的一等语句。在解析器定义 edb/edgeql/parser/grammar/statements.py#L290-L300 中,AnalyzeStmt非终结符支持两种归约形式:

  • reduce_ANALYZE_ExprStmtanalyze <query>的基本形态;
  • reduce_ANALYZE_NamedTuple_ExprStmtanalyze (参数 := 值) <query>的带参形态——这正是上文(buffers := True)(execute := False)语法的来源。

由此可以确认:无论通过gel analyzeCLI 命令、REPL 的analyze前缀还是\analyze反斜杠命令,最终都归约到同一套语法树并复用同一条分析执行链路,三种入口的底层行为保持一致。而gel analyze命令行本身则是把「连接实例 + 发送带analyze前缀的查询 + 格式化结果」封装成了单条命令,属于对 EdgeQLanalyze语句的 CLI 层包装。

权限说明

analyze属于特权操作。自 Gel 7.0 起,基于角色的访问控制(RBAC)将ANALYZE与 dump、restore、ADMINISTER、DESCRIBE 一同纳入受限操作集合(见 docs/resources/changelog/7_x.rst#L186),因此在共享实例上执行gel analyze前,需确保当前角色具备相应权限。

性能分析的实战建议

  1. 先粗后细:默认粗粒度输出足以定位「哪个形状最贵」;确认瓶颈后再用--expand查看该节点的扫描/连接策略,避免一开始就被海量细粒度信息淹没。
  2. 关注 Cost 与 Loops 的比值Loops不为 1 的嵌套节点意味着其父节点存在循环展开,即使单次 Cost 不高,乘以循环次数后也可能成为热点;root行的高Cost往往意味着查询需要全量扫描或缺少索引。
  3. 善用 JSON 归档:对每次上线前的关键查询运行gel analyze --debug-output-file,把 JSON 作为基准归档;性能回归时用--read-json对比新旧计划,快速锁定变化。
  4. 结合 REPL 与 UI:交互式调优时,CLI REPL 的analyze+\expand组合与 UI 查询构建器的可视化分析(gel ui唤起)能提供更直观的图形化视角,适合反复调整查询形状的探索场景。
  5. 与索引、迁移配合:分析发现SeqScan后,可结合 docs/reference/datamodel/indexes.rst 的索引定义与 docs/reference/datamodel/migrations.rst 的迁移流程落地优化,并用测试套件中的_assert_index_use思路(tests/test_edgeql_explain.py#L69-L88)在 CI 中断言索引确实生效。

至此,从命令语法、输出解读、展开与 JSON 工作流,到底层解析器实现与测试证据,gel analyze的完整使用图景已经清晰:它不仅是终端里的一条调试命令,更是 Gel 生态中衔接查询编写、执行计划与性能治理的核心工具。

  • 数据库
  • 图数据库
  • 关系型数据库

【免费下载链接】edgedb

Gel supercharges Postgres with a modern data model, graph queries, Auth & AI solutions, and much more.

项目地址:https://gitcode.com/gh_mirrors/ed/edgedb
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询