使用 EXPLAIN 和 PROFILE 进行性能调试
EXPLAIN 和 PROFILE 是 Cypher 查询执行命令,可用于检查查询执行计划,并在查询执行期间收集性能指标。
快速参考
- EXPLAIN:查看执行计划,但不实际执行查询
- PROFILE:执行查询,并收集每个算子的耗时和行数统计信息
概述
EXPLAIN 模式
EXPLAIN 会显示查询的物理执行计划,但不会实际执行该查询。这在以下场景中非常有用:
- 理解查询优化器如何规划您的查询
- 在执行前识别次优的查询结构
- 调试复杂的连接(JOIN)和聚合操作
结果:返回算子树结构,不返回任何数据行。
PROFILE 模式
PROFILE 执行您的查询,并收集每个算子(operator)的详细指标。该模式适用于以下场景:
- 识别慢查询中的性能瓶颈
- 对比不同查询结构的执行时间
- 理解数据分布对查询执行的影响
结果:
- 查询返回的数据行 —— 查询实际返回的结果集
- 算子树结构 —— 执行计划(与 EXPLAIN 输出相同)
- 各算子指标 —— 每个算子的执行时间和处理行数
示例
以下示例使用 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)中需关注以下几点:
-
扫描操作主导早期阶段:
ScanWithGPredOpr(扫描满足谓词条件的节点)耗时 12.75 毫秒,占总耗时(52.99 毫秒)的约 24%。此处将全部 76,830 条评论加载进内存——这是必要的基础开销。 -
边扩展是显著瓶颈:两个
EdgeExpandVOpr(沿关系展开以生成新行)操作合计耗时 22.68 毫秒(占总耗时的 43%),尽管其输出稳定在 38,044 行。这表明本例中边查找开销相对较高;若该查询性能不佳,建议为comment→post和post→person关系建立索引。 -
聚合操作高效:
GroupByOpr(按键分组并应用聚合函数)仅用 7.88 毫秒便将 38,044 行压缩为 7,325 个分组。说明相较于前期的边遍历,分组操作本身非常快速。 -
优化器融合了 ORDER BY 与 LIMIT:
ProjectOrderByOprBeta(融合型算子:单次遍历完成排序与 LIMIT)仅耗时 0.10 毫秒,即从 7,325 行中选出前 10 行。这体现了优化器能智能合并ORDER BY和LIMIT,避免对全部中间结果进行完整排序。 -
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 个元组 │
└───────────────────────────────────────┘此执行计划中需关注的要点:
-
扫描开销显著:
ScanWithGPredOpr耗时 26.20ms(占总时间的 27%),扫描了 78,976 个论坛。对于参与度类查询,若以较大集合(如论坛)而非较小集合(如成员)作为起点,可能影响早期执行性能。 -
边展开开销与示例 1 相当:
EdgeExpandVOpr耗时 24.70ms,用于遍历论坛到成员的关系,结果缩减为 21,636 行。该开销与示例 1 接近,表明在不同查询模式下,边查找的固有开销保持一致。 -
IntersectOprMultip:多路径关联瓶颈:IntersectOprMultip(用于对齐多个独立关系路径以找出匹配项)耗时 23.41ms(占总时间的 24%),需对齐三条独立路径:- 论坛 → 成员(
forumHasMember) - 论坛 → 帖子(
forumContainerOf) - 成员 → 帖子(
personLikesPost)
高开销反映了计算所有满足“成员加入了某论坛且点赞了该论坛内某帖子”的有效三元组
(forum, member, post)所需的关联代价。行数维持在 21,636 不变,说明未发生数据爆炸,仅是关联操作本身计算成本高昂。 - 论坛 → 成员(
-
GroupByOpr:对去重计数的中等开销:GroupByOpr在 9.58ms 内将 21,636 行聚合为 16,254 个分组。分组数量减少表明许多(forum, member)组合在同一个论坛内点赞了多个帖子。 -
优化启示:若该查询响应缓慢,瓶颈在于
IntersectOprMultip关联步骤(23.41ms),而非后续聚合(9.58ms)。可考虑以下优化措施:- 为
forumHasMember和forumContainerOf关系建立索引; - 重写查询,在执行关联前先减少候选集(例如,预先按论坛规模进行过滤)。
- 为
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)中需重点关注以下几点:
-
扫描操作确立性能基线:
ScanWithGPredOpr耗时 9.23ms,用于构建模式匹配所需的初始工作集。这是图遍历开始前的基础开销。 -
边展开操作表现出稳定开销:
EdgeExpandVOpr耗时 8.40ms,用于遍历personHasInterest关系,共生成 21,636 行。其耗时与初始扫描(9.23ms)接近,表明在此查询中,每次边查找均带来相对稳定的单位操作开销。 -
IntersectOprMultip具有高度选择性:该算子耗时 6.95ms,将输入的 21,636 行大幅缩减至 715 行(降幅达 97%)。它代表了查询的核心逻辑:找出同时满足“用户声明对某标签感兴趣”且“用户点赞过带该标签的帖子”的所有(person, tag)对。如此高的选择性说明,在当前数据集中,用户声明的兴趣与实际点赞内容之间重合度较低。 -
下游操作效率极高:经过交集运算后仅剩 715 个候选行,后续各算子执行极快:
ProjectOpr:1.05msGroupByOpr: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 报告中需关注以下几点:
-
扫描操作作用于小规模集合:
ScanWithGPredOpr耗时 2.64ms,扫描了 903 个person节点。从模式中最小的实体(person节点,而非post或comment)开始扫描,可使早期扫描操作更高效。 -
多跳遍历在大规模数据下仍保持高效:一系列算子共同完成两跳遍历(
person → organisation → place):EdgeExpandEOpr(展开边以获取边–节点对):耗时 2.56ms(从 person 到其工作关系)GetVFromEdgesOpr(从边结果中提取目标节点):耗时 2.02ms(提取目标organisation节点)EdgeExpandVOpr:耗时 1.38ms(从organisation到其所在地place)
多跳遍历总开销约 6ms;考虑到共执行了三次关系查找,该开销属合理范围。
-
中间行数全程可控:工作集增长至 1,953 行(即 person–organisation 对),并在后续直至聚合阶段均维持该基数。这一较小的基数是实现快速执行的关键——未发生中间结果行数爆炸。
-
基于边属性的聚合操作高效:
GroupByOpr在仅 0.78ms 内将 1,953 行聚合为 796 个分组(即place × organisation组合),同时计算COUNT(DISTINCT person.id)、MIN(workFrom)和MAX(workFrom)。这表明:当行数处于合理范围时,对边属性进行聚合并统计去重实体的操作非常高效。 -
整体执行时间印证查询效率:总耗时仅 10.73ms,说明多跳遍历类查询可在如下条件下实现极高的执行效率:
- 从较小的节点集合起步(此处为 903 个
person节点) - 遍历过程不引发行数爆炸
- 聚合操作作用于紧凑的工作集
- 从较小的节点集合起步(此处为 903 个
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)中需重点关注以下几点:
-
第一跳扩展幅度适中:首个
EdgeExpandVOpr扫描了 903 个person节点,并遍历其personKnows关系,生成 6,626 行结果(约 7 倍扩展)。耗时 14.95 毫秒——属于稳定的边查找开销。 -
第二跳引发行数爆炸式增长:第二个
EdgeExpandVOpr是关键瓶颈。它耗时 14.82 毫秒,将 6,626 行(person → friend)扩展为 92,285 行(person → friend → friend-of-friend),即 14 倍扩展。这表明:在每个用户拥有大量连接的社交网络中,多跳“朋友的朋友”扩展呈指数级增长。 -
WHERE 过滤条件高度选择性或实际无效:
SelectOpr(基于 WHERE 条件过滤行)在 13.89 毫秒内处理p1.id <> p3.id条件,但输出仍为 92,285 行,说明以下两种情况之一成立:- 数据集中几乎不存在自环型 FOF 路径(即
p1 == p3的情况) - 社交网络结构天然导致此类环路极为罕见
- 数据集中几乎不存在自环型 FOF 路径(即
这揭示了一个重要原则:并非所有 WHERE 条件都能带来显著的过滤效果;理解数据分布对查询优化至关重要。
-
大规模行集上的投影开销:
ProjectOpr耗时 8.34 毫秒,从 92,285 行中提取并格式化六个输出字段(p1/p2/p3的姓名)。该开销虽属中等,但随行数线性增长。 -
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 时非常有用。