Skip to Content
Cypher 手册执行计划分析

使用 EXPLAIN 和 PROFILE 进行性能调试

EXPLAIN 和 PROFILE 是 Cypher 查询执行命令,可用于检查查询执行计划,并在查询执行期间收集性能指标。

快速参考

  • EXPLAIN:查看执行计划,但不实际执行查询
  • PROFILE:执行查询,并收集每个算子的耗时和行数统计信息

概述

EXPLAIN 模式

EXPLAIN 会显示查询的物理执行计划,但不会实际执行该查询。这在以下场景中非常有用:

  • 理解查询优化器如何规划您的查询
  • 在执行前识别次优的查询结构
  • 调试复杂的连接(JOIN)和聚合操作

结果:返回算子树结构,不返回任何数据行。

PROFILE 模式

PROFILE 执行您的查询,并收集每个算子(operator)的详细指标。该模式适用于以下场景:

  • 识别慢查询中的性能瓶颈
  • 对比不同查询结构的执行时间
  • 理解数据分布对查询执行的影响

结果

  1. 查询返回的数据行 —— 查询实际返回的结果集
  2. 算子树结构 —— 执行计划(与 EXPLAIN 输出相同)
  3. 各算子指标 —— 每个算子的执行时间和处理行数

示例

以下示例使用 ldbc_sample 数据集。

PROFILE 示例

1. 哪些帖子引发了最多的讨论?

按直接评论数量找出评论数最多的前 10 篇帖子,并识别其作者。

PROFILE MATCH (c:comment)-[:commentReplyOfPost]->(p:post)-[:postHasCreator]->(author:person) RETURN p.id, author.firstName, author.lastName, COUNT(c.id) AS direct_reply_count ORDER BY direct_reply_count DESC LIMIT 10;

输出:

+---------------+--------------------------+----------------------+----------------------+ | _2_p.id | _6_author.firstName | _6_author.lastName | direct_reply_count | +===============+==========================+======================+======================+ | 1030792245903 | Bona Pinder Yayumayalolo | Collinet | 19 | +---------------+--------------------------+----------------------+----------------------+ | 343597401905 | Abby | Hassan | 18 | +---------------+--------------------------+----------------------+----------------------+ | 618475479931 | Hao | Liu | 18 | +---------------+--------------------------+----------------------+----------------------+ | 1030792175730 | Yang | Zhang | 17 | +---------------+--------------------------+----------------------+----------------------+ | 343597520846 | Abdul-Malik | Binalshibh | 17 | +---------------+--------------------------+----------------------+----------------------+ | 893353316266 | Emperor of Brazil | Dom Pedro II | 17 | +---------------+--------------------------+----------------------+----------------------+ | 549755856528 | Camila | Alves | 17 | +---------------+--------------------------+----------------------+----------------------+ | 274877914558 | Pol | Dara | 17 | +---------------+--------------------------+----------------------+----------------------+ | 893353214109 | Dumitru | David | 16 | +---------------+--------------------------+----------------------+----------------------+ | 412316913317 | Isabel | Fernandez | 16 | +---------------+--------------------------+----------------------+----------------------+ ╔════════════════════════════════════════╗ ║ PROFILE 报告 ║ ╚════════════════════════════════════════╝ 总输出元组数:10 总耗时:52.99 毫秒 ┌───────────────────────────────────────┐ │ ScanWithGPredOpr │ ├───────────────────────────────────────┤ │ 耗时:12.75 毫秒 | 行数:76830 元组 │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ EdgeExpandVOpr │ ├───────────────────────────────────────┤ │ 耗时:12.16 毫秒 | 行数:38044 元组 │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ EdgeExpandVOpr │ ├───────────────────────────────────────┤ │ 耗时:10.52 毫秒 | 行数:38044 元组 │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ ProjectOpr │ ├───────────────────────────────────────┤ │ 耗时:9.57 毫秒 | 行数:38044 元组 │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ GroupByOpr │ ├───────────────────────────────────────┤ │ 耗时:7.88 毫秒 | 行数:7325 元组 │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ ProjectOrderByOprBeta │ ├───────────────────────────────────────┤ │ 耗时:0.10 毫秒 | 行数:10 元组 │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ ProjectOpr │ ├───────────────────────────────────────┤ │ 耗时:0.00 毫秒 | 行数:10 元组 │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ SinkOpr │ ├───────────────────────────────────────┤ │ 耗时:0.00 毫秒 | 行数:10 元组 │ └───────────────────────────────────────┘

在该执行计划(PROFILE)中需关注以下几点:

  1. 扫描操作主导早期阶段ScanWithGPredOpr(扫描满足谓词条件的节点)耗时 12.75 毫秒,占总耗时(52.99 毫秒)的约 24%。此处将全部 76,830 条评论加载进内存——这是必要的基础开销。

  2. 边扩展是显著瓶颈:两个 EdgeExpandVOpr(沿关系展开以生成新行)操作合计耗时 22.68 毫秒(占总耗时的 43%),尽管其输出稳定在 38,044 行。这表明本例中边查找开销相对较高;若该查询性能不佳,建议为 comment→postpost→person 关系建立索引。

  3. 聚合操作高效GroupByOpr(按键分组并应用聚合函数)仅用 7.88 毫秒便将 38,044 行压缩为 7,325 个分组。说明相较于前期的边遍历,分组操作本身非常快速。

  4. 优化器融合了 ORDER BY 与 LIMITProjectOrderByOprBeta(融合型算子:单次遍历完成排序与 LIMIT)仅耗时 0.10 毫秒,即从 7,325 行中选出前 10 行。这体现了优化器能智能合并 ORDER BYLIMIT,避免对全部中间结果进行完整排序。

  5. LIMIT 并不减少上游计算量:注意所有 38,044 条评论记录均流经 GroupByOpr 后才被缩减至最终 10 行。LIMIT 子句仅缩短输出结果,而非减少实际执行工作量——因此,相比调整 LIMIT,更有效的优化方向是尽早过滤(例如:对评论添加时间范围约束)。

2. 哪些论坛成员正在点赞其加入的论坛内的帖子?

这是一个实际的用户参与度查询:它将社区成员身份与论坛内的真实活跃行为相关联。

PROFILE MATCH (f:forum)-[:forumHasMember]->(member:person), (f)-[:forumContainerOf]->(p:post), (member)-[:personLikesPost]->(p) RETURN f.title, member.firstName, member.lastName, COUNT(DISTINCT p.id) AS liked_posts_in_forum;

输出:

+----------------------------+-----------------------+----------------------+------------------------+ | _0_f.title | _2_member.firstName | _2_member.lastName | liked_posts_in_forum | +============================+=======================+======================+========================+ | Album 1 of Mahinda Perera | Dumitru | David | 2 | +----------------------------+-----------------------+----------------------+------------------------+ | Album 1 of Mahinda Perera | Walter | Becker | 1 | +----------------------------+-----------------------+----------------------+------------------------+ | Album 3 of Mahinda Perera | Dumitru | David | 1 | +----------------------------+-----------------------+----------------------+------------------------+ | Album 9 of Mahinda Perera | Walter | Becker | 2 | +----------------------------+-----------------------+----------------------+------------------------+ | Album 9 of Mahinda Perera | Anh | Nguyen | 1 | +----------------------------+-----------------------+----------------------+------------------------+ | Album 10 of Mahinda Perera | Dumitru | David | 1 | +----------------------------+-----------------------+----------------------+------------------------+ | ... | ... | ... | ... | +----------------------------+-----------------------+----------------------+------------------------+ ╔════════════════════════════════════════╗ ║ PROFILE 报告 ║ ╚════════════════════════════════════════╝ 总输出元组数:16254 总耗时:96.16 毫秒 ┌───────────────────────────────────────┐ │ ScanWithGPredOpr │ ├───────────────────────────────────────┤ │ 耗时:26.20ms | 行数:78976 个元组 │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ EdgeExpandVOpr │ ├───────────────────────────────────────┤ │ 耗时:24.70ms | 行数:21636 个元组 │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ IntersectOprMultip │ ├───────────────────────────────────────┤ │ 耗时:23.41ms | 行数:21636 个元组 │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ ProjectOpr │ ├───────────────────────────────────────┤ │ 耗时:12.27ms | 行数:21636 个元组 │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ GroupByOpr │ ├───────────────────────────────────────┤ │ 耗时:9.58ms | 行数:16254 个元组 │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ ProjectOpr │ ├───────────────────────────────────────┤ │ 耗时:0.00ms | 行数:16254 个元组 │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ SinkOpr │ ├───────────────────────────────────────┤ │ 耗时:0.00ms | 行数:16254 个元组 │ └───────────────────────────────────────┘

此执行计划中需关注的要点:

  1. 扫描开销显著ScanWithGPredOpr 耗时 26.20ms(占总时间的 27%),扫描了 78,976 个论坛。对于参与度类查询,若以较大集合(如论坛)而非较小集合(如成员)作为起点,可能影响早期执行性能。

  2. 边展开开销与示例 1 相当EdgeExpandVOpr 耗时 24.70ms,用于遍历论坛到成员的关系,结果缩减为 21,636 行。该开销与示例 1 接近,表明在不同查询模式下,边查找的固有开销保持一致。

  3. IntersectOprMultip:多路径关联瓶颈IntersectOprMultip(用于对齐多个独立关系路径以找出匹配项)耗时 23.41ms(占总时间的 24%),需对齐三条独立路径:

    • 论坛 → 成员(forumHasMember
    • 论坛 → 帖子(forumContainerOf
    • 成员 → 帖子(personLikesPost

    高开销反映了计算所有满足“成员加入了某论坛且点赞了该论坛内某帖子”的有效三元组 (forum, member, post) 所需的关联代价。行数维持在 21,636 不变,说明未发生数据爆炸,仅是关联操作本身计算成本高昂。

  4. GroupByOpr:对去重计数的中等开销GroupByOpr 在 9.58ms 内将 21,636 行聚合为 16,254 个分组。分组数量减少表明许多 (forum, member) 组合在同一个论坛内点赞了多个帖子。

  5. 优化启示:若该查询响应缓慢,瓶颈在于 IntersectOprMultip 关联步骤(23.41ms),而非后续聚合(9.58ms)。可考虑以下优化措施:

    • forumHasMemberforumContainerOf 关系建立索引;
    • 重写查询,在执行关联前先减少候选集(例如,预先按论坛规模进行过滤)。

3. 用户是否喜欢与其声明兴趣相匹配的内容?

这是一个贴近实际应用的个性化或推荐效果分析查询。

PROFILE MATCH (person:person)-[:personHasInterest]->(tag:tag), (person)-[:personLikesPost]->(post:post)-[:postHasTag]->(tag) RETURN person.firstName, person.lastName, tag.name, COUNT(DISTINCT post.id) AS matching_liked_posts;

输出结果:

+----------------------------+----------------------+----------------------------+------------------------+ | _0_person.firstName | _0_person.lastName | _2_tag.name | matching_liked_posts | +============================+======================+============================+========================+ | Ali | Diori | Henry_Wadsworth_Longfellow | 1 | +----------------------------+----------------------+----------------------------+------------------------+ | Antonio | Alvarez | Wolfgang_Amadeus_Mozart | 1 | +----------------------------+----------------------+----------------------------+------------------------+ | Ken | Yamada | Franz_Kafka | 1 | +----------------------------+----------------------+----------------------------+------------------------+ | Rahul | Nair | Hamid_Karzai | 2 | +----------------------------+----------------------+----------------------------+------------------------+ | Fritz | Richter | Orson_Welles | 1 | +----------------------------+----------------------+----------------------------+------------------------+ | Walter | Schmidt | United_Arab_Emirates | 1 | +----------------------------+----------------------+----------------------------+------------------------+ | ... | ... | ... | ... | +----------------------------+----------------------+----------------------------+------------------------+ ╔════════════════════════════════════════╗ ║ PROFILE 报告 ║ ╚════════════════════════════════════════╝ 总输出元组数:503 总耗时:26.17 毫秒 ┌───────────────────────────────────────┐ │ ScanWithGPredOpr │ ├───────────────────────────────────────┤ │ 耗时:9.23ms | 输出行数:78976 元组 │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ EdgeExpandVOpr │ ├───────────────────────────────────────┤ │ 耗时:8.40ms | 输出行数:21636 元组 │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ IntersectOprMultip │ ├───────────────────────────────────────┤ │ 耗时:6.95ms | 输出行数: 715 元组 │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ ProjectOpr │ ├───────────────────────────────────────┤ │ 耗时:1.05ms | 输出行数: 715 元组 │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ GroupByOpr │ ├───────────────────────────────────────┤ │ 耗时:0.54ms | 输出行数: 503 元组 │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ ProjectOpr │ ├───────────────────────────────────────┤ │ 耗时:0.00ms | 输出行数: 503 元组 │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ SinkOpr │ ├───────────────────────────────────────┤ │ 耗时:0.00ms | 输出行数: 503 元组 │ └───────────────────────────────────────┘

在该执行计划(PROFILE)中需重点关注以下几点:

  1. 扫描操作确立性能基线ScanWithGPredOpr 耗时 9.23ms,用于构建模式匹配所需的初始工作集。这是图遍历开始前的基础开销。

  2. 边展开操作表现出稳定开销EdgeExpandVOpr 耗时 8.40ms,用于遍历 personHasInterest 关系,共生成 21,636 行。其耗时与初始扫描(9.23ms)接近,表明在此查询中,每次边查找均带来相对稳定的单位操作开销。

  3. IntersectOprMultip 具有高度选择性:该算子耗时 6.95ms,将输入的 21,636 行大幅缩减至 715 行(降幅达 97%)。它代表了查询的核心逻辑:找出同时满足“用户声明对某标签感兴趣”且“用户点赞过带该标签的帖子”的所有 (person, tag) 对。如此高的选择性说明,在当前数据集中,用户声明的兴趣与实际点赞内容之间重合度较低。

  4. 下游操作效率极高:经过交集运算后仅剩 715 个候选行,后续各算子执行极快:

    • ProjectOpr:1.05ms
    • GroupByOpr:0.54ms(将 715 行聚合为 503 个不同的用户-标签组合)

4. 公司在各地区及各招聘时段的分布情况如何?

该查询结合了人员工作关系、组织所在地,并对边属性进行聚合。

PROFILE MATCH (person:person)-[w:personWorkAt]->(org:organisation)-[:organisationIsLocatedIn]->(place:place) RETURN place.name, org.name, COUNT(DISTINCT person.id) AS employee_count, MIN(w.workFrom) AS earliest_work_from, MAX(w.workFrom) AS latest_work_from;

输出结果:

+-----------------+---------------------------------------+------------------+----------------------+--------------------+ | _6_place.name | _2_org.name | employee_count | earliest_work_from | latest_work_from | +=================+=======================================+==================+======================+====================+ | Sri_Lanka | SriLankan_Airlines | 2 | 2007 | 2013 | +-----------------+---------------------------------------+------------------+----------------------+--------------------+ | Sri_Lanka | Aero_Lanka | 4 | 2003 | 2013 | +-----------------+---------------------------------------+------------------+----------------------+--------------------+ | Morocco | Atlas_Blue | 5 | 2002 | 2012 | +-----------------+---------------------------------------+------------------+----------------------+--------------------+ | China | Spring_Airlines | 10 | 1999 | 2010 | +-----------------+---------------------------------------+------------------+----------------------+--------------------+ | China | Sichuan_Airlines | 11 | 2004 | 2011 | +-----------------+---------------------------------------+------------------+----------------------+--------------------+ | Netherlands | Quick_Airways_Holland | 3 | 2005 | 2006 | +-----------------+---------------------------------------+------------------+----------------------+--------------------+ | Germany | Luftfahrtgesellschaft_Walter | 2 | 2005 | 2007 | +-----------------+---------------------------------------+------------------+----------------------+--------------------+ | ... | ... | ... | ... | ... | +-----------------+---------------------------------------+------------------+----------------------+--------------------+ ╔════════════════════════════════════════╗ ║ PROFILE 报告 ║ ╚════════════════════════════════════════╝ 总输出元组数:796 总耗时:10.73 毫秒 ┌───────────────────────────────────────┐ │ ScanWithGPredOpr │ ├───────────────────────────────────────┤ │ 耗时:2.64ms | 行数:903 个元组 │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ EdgeExpandEOpr │ ├───────────────────────────────────────┤ │ 耗时:2.56ms | 行数:1953 个元组 │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ GetVFromEdgesOpr │ ├───────────────────────────────────────┤ │ 耗时:2.02ms | 行数:1953 个元组 │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ EdgeExpandVOpr │ ├───────────────────────────────────────┤ │ 耗时:1.38ms | 行数:1953 个元组 │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ ProjectOpr │ ├───────────────────────────────────────┤ │ 耗时:1.34ms | 行数:1953 个元组 │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ GroupByOpr │ ├───────────────────────────────────────┤ │ 耗时:0.78ms | 行数:796 个元组 │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ ProjectOpr │ ├───────────────────────────────────────┤ │ 耗时:0.00ms | 行数:796 个元组 │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ SinkOpr │ ├───────────────────────────────────────┤ │ 耗时:0.00ms | 行数:796 个元组 │ └───────────────────────────────────────┘

本 Profile 报告中需关注以下几点:

  1. 扫描操作作用于小规模集合ScanWithGPredOpr 耗时 2.64ms,扫描了 903 个 person 节点。从模式中最小的实体(person 节点,而非 postcomment)开始扫描,可使早期扫描操作更高效。

  2. 多跳遍历在大规模数据下仍保持高效:一系列算子共同完成两跳遍历(person → organisation → place):

    • EdgeExpandEOpr(展开边以获取边–节点对):耗时 2.56ms(从 person 到其工作关系)
    • GetVFromEdgesOpr(从边结果中提取目标节点):耗时 2.02ms(提取目标 organisation 节点)
    • EdgeExpandVOpr:耗时 1.38ms(从 organisation 到其所在地 place

    多跳遍历总开销约 6ms;考虑到共执行了三次关系查找,该开销属合理范围。

  3. 中间行数全程可控:工作集增长至 1,953 行(即 person–organisation 对),并在后续直至聚合阶段均维持该基数。这一较小的基数是实现快速执行的关键——未发生中间结果行数爆炸。

  4. 基于边属性的聚合操作高效GroupByOpr 在仅 0.78ms 内将 1,953 行聚合为 796 个分组(即 place × organisation 组合),同时计算 COUNT(DISTINCT person.id)MIN(workFrom)MAX(workFrom)。这表明:当行数处于合理范围时,对边属性进行聚合并统计去重实体的操作非常高效。

  5. 整体执行时间印证查询效率:总耗时仅 10.73ms,说明多跳遍历类查询可在如下条件下实现极高的执行效率:

    • 从较小的节点集合起步(此处为 903 个 person 节点)
    • 遍历过程不引发行数爆炸
    • 聚合操作作用于紧凑的工作集

5. 朋友的朋友关系扩展的速度有多快?

该查询在调试推荐类图扩展逻辑时非常有用。

PROFILE MATCH (p1:person)-[:personKnows]->(p2:person)-[:personKnows]->(p3:person) WHERE p1.id <> p3.id RETURN p1.firstName, p1.lastName, p2.firstName, p2.lastName, p3.firstName, p3.lastName LIMIT 10;

输出:

+-------------------+------------------+-------------------+------------------+-------------------+------------------+ | _0_p1.firstName | _0_p1.lastName | _2_p2.firstName | _2_p2.lastName | _6_p3.firstName | _6_p3.lastName | +===================+==================+===================+==================+===================+==================+ | Mahinda | Perera | Dumitru | David | Nicolae | Antonescu | +-------------------+------------------+-------------------+------------------+-------------------+------------------+ | Mahinda | Perera | Dumitru | David | Amit | Sharma | +-------------------+------------------+-------------------+------------------+-------------------+------------------+ | Mahinda | Perera | Dumitru | David | Jie | Wang | +-------------------+------------------+-------------------+------------------+-------------------+------------------+ | Mahinda | Perera | Dumitru | David | Hans | Berg | +-------------------+------------------+-------------------+------------------+-------------------+------------------+ | Mahinda | Perera | Dumitru | David | Mihai | David | +-------------------+------------------+-------------------+------------------+-------------------+------------------+ | Mahinda | Perera | Dumitru | David | Jan | Zakrzewski | +-------------------+------------------+-------------------+------------------+-------------------+------------------+ | Mahinda | Perera | Dumitru | David | Victor | Antonescu | +-------------------+------------------+-------------------+------------------+-------------------+------------------+ | Mahinda | Perera | Dumitru | David | Chris | Hall | +-------------------+------------------+-------------------+------------------+-------------------+------------------+ | Mahinda | Perera | Dumitru | David | Alexei | Goma | +-------------------+------------------+-------------------+------------------+-------------------+------------------+ | Mahinda | Perera | Dumitru | David | Alec | Cheng | +-------------------+------------------+-------------------+------------------+-------------------+------------------+ ╔════════════════════════════════════════╗ ║ PROFILE REPORT ║ ╚════════════════════════════════════════╝ Total output tuples: 10 Total elapsed time: 68.13 ms ┌───────────────────────────────────────┐ │ ScanWithGPredOpr │ ├───────────────────────────────────────┤ │ time: 15.04ms | rows: 903 tuples │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ EdgeExpandVOpr │ ├───────────────────────────────────────┤ │ time: 14.95ms | rows: 6626 tuples │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ EdgeExpandVOpr │ ├───────────────────────────────────────┤ │ time: 14.82ms | rows: 92285 tuples │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ SelectOpr │ ├───────────────────────────────────────┤ │ time: 13.89ms | rows: 92285 tuples │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ ProjectOpr │ ├───────────────────────────────────────┤ │ time: 8.34ms | rows: 92285 tuples │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ LimitOpr │ ├───────────────────────────────────────┤ │ time: 1.09ms | rows: 10 tuples │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ SinkOpr │ ├───────────────────────────────────────┤ │ time: 0.00ms | rows: 10 tuples │ └───────────────────────────────────────┘

在此执行计划(PROFILE)中需重点关注以下几点:

  1. 第一跳扩展幅度适中:首个 EdgeExpandVOpr 扫描了 903 个 person 节点,并遍历其 personKnows 关系,生成 6,626 行结果(约 7 倍扩展)。耗时 14.95 毫秒——属于稳定的边查找开销。

  2. 第二跳引发行数爆炸式增长:第二个 EdgeExpandVOpr 是关键瓶颈。它耗时 14.82 毫秒,将 6,626 行(person → friend)扩展为 92,285 行(person → friend → friend-of-friend),即 14 倍扩展。这表明:在每个用户拥有大量连接的社交网络中,多跳“朋友的朋友”扩展呈指数级增长。

  3. WHERE 过滤条件高度选择性或实际无效SelectOpr(基于 WHERE 条件过滤行)在 13.89 毫秒内处理 p1.id <> p3.id 条件,但输出仍为 92,285 行,说明以下两种情况之一成立:

    • 数据集中几乎不存在自环型 FOF 路径(即 p1 == p3 的情况)
    • 社交网络结构天然导致此类环路极为罕见

这揭示了一个重要原则:并非所有 WHERE 条件都能带来显著的过滤效果;理解数据分布对查询优化至关重要。

  1. 大规模行集上的投影开销ProjectOpr 耗时 8.34 毫秒,从 92,285 行中提取并格式化六个输出字段(p1/p2/p3 的姓名)。该开销虽属中等,但随行数线性增长。

  2. LIMIT 不会阻止上游计算LimitOpr 最终仅用 1.09 毫秒便将 92,285 行缩减为 10 行输出。然而,全部 92,285 行必须先流经扫描、两次边扩展、过滤及投影等阶段,LIMIT 才生效。因此,整个查询的总耗时主要由这些上游操作决定,而非最终的输出限制。

EXPLAIN 示例

EXPLAIN 使用与 PROFILE 相同的格式化报告布局,但不会实际执行查询。因此,所有耗时均为 0.00 ms,所有输出行数均为 0

EXPLAIN MATCH (c:comment)-[:commentReplyOfPost]->(p:post)-[:postHasCreator]->(author:person) RETURN p.id, author.firstName, author.lastName, COUNT(c.id) AS direct_reply_count ORDER BY direct_reply_count DESC LIMIT 10;

示例输出:

No results (total records: 0) ╔════════════════════════════════════════╗ ║ PROFILE REPORT ║ ╚════════════════════════════════════════╝ Total output tuples: 0 Total elapsed time: 0.00 ms ┌───────────────────────────────────────┐ │ ScanWithGPredOpr │ ├───────────────────────────────────────┤ │ time: 0.00ms | rows: 0 tuples │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ EdgeExpandVOpr │ ├───────────────────────────────────────┤ │ time: 0.00ms | rows: 0 tuples │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ EdgeExpandVOpr │ ├───────────────────────────────────────┤ │ time: 0.00ms | rows: 0 tuples │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ ProjectOpr │ ├───────────────────────────────────────┤ │ time: 0.00ms | rows: 0 tuples │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ GroupByOpr │ ├───────────────────────────────────────┤ │ time: 0.00ms | rows: 0 tuples │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ ProjectOrderByOprBeta │ ├───────────────────────────────────────┤ │ time: 0.00ms | rows: 0 tuples │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ ProjectOpr │ ├───────────────────────────────────────┤ │ time: 0.00ms | rows: 0 tuples │ └───────────────────────────────────────┘ ┌───────────────────────────────────────┐ │ SinkOpr │ ├───────────────────────────────────────┤ │ time: 0.00ms | rows: 0 tuples │ └───────────────────────────────────────┘

这使得 EXPLAIN 在您希望先验证执行计划、仅在计划看起来合理后再运行 PROFILE 时非常有用。

Last updated on