EXPLAIN¶
EXPLAIN命令显示查询的执行计划。与执行查询不同,EXPLAIN命令概述了查询执行期间采取的步骤,有利于调试和优化查询。
若使用 ngql 命令行工具,可通过:planstyle命令切换执行计划的展示形式(嵌套/表格/盒状)。默认风格为嵌套视图。更多信息,请参见 ngql 的设置执行计划展示视图。
优化管线
EXPLAIN命令支持查看查询在不同优化阶段的执行计划。完整的优化管线为:
RAW:优化前的原始逻辑计划。DECORRELATED:子查询解关联后的逻辑计划。CBO:CBO(基于代价的优化器)阶段后的逻辑计划。- 默认(不指定阶段):全部优化完成后的最终执行计划。
通过查看不同阶段的计划,可以定位优化过程中的具体问题,例如子查询改写是否生效、Join 顺序是否合理。
语法¶
- explain_command
explain_command ::=
'EXPLAIN' ( 'RAW' | 'CBO' | 'DECORRELATED' )? ( 'FORMAT' '=' '"' ( 'VERBOSE' | 'DEFAULT' ) '"' )? gql_query
参数¶
RAW | CBO | DECORRELATED¶
指定查看不同优化阶段的执行计划。不同阶段对应查询优化管线中的不同处理节点。
各阶段说明如下:
| 阶段 | 说明 |
|---|---|
RAW |
返回优化前的原始逻辑计划。 |
DECORRELATED |
返回子查询解关联后的逻辑计划。此阶段将相关子查询(即依赖外层变量、每行都需重复执行内层查询的子查询)改写为等价的非嵌套形式(如 Join 或聚合),使其可以进入后续的常规优化流程。 |
CBO |
返回 CBO(基于代价的优化器)阶段后的逻辑计划。此阶段侧重于图模式匹配中的 Join 重排序与代价决策,并非所有查询都会经过此阶段,仅在满足条件的图模式/Join 重排场景下生效。MATCH模式的展开顺序重排由enable_reorder单独控制,且默认值为false。 |
如果省略此参数,则返回全部优化完成后的最终执行计划。
FORMAT = "VERBOSE" | FORMAT = "DEFAULT"¶
执行计划的输出格式有两种:VERBOSE和DEFAULT。
VERBOSE格式更加详细,适用于调试和优化查询。当指定FORMAT = VERBOSE选项时,使用VERBOSE格式。
DEFAULT格式是VERBOSE格式的简化版本。当省略FORMAT = DEFAULT和FORMAT = "VERBOSE"选项时,默认使用DEFAULT格式。
以上两种格式的返回信息如下:
| 参数 | 描述 |
|---|---|
plan |
表示执行计划的算子。算子按照执行顺序从下到上列出。 |
details |
提供有关算子的详细信息,包括将访问的点和边的数据。 |
columns |
表示算子在执行过程中处理的列。只有当指定FORMAT = VERBOSE时,该列才会显示。 |
gql_query¶
待显示其执行计划的 GQL 查询。
示例¶
以下示例基于示例数据集。
指定DEFAULT查看优化后的执行计划¶
下例显式指定FORMAT = "DEFAULT",等同于省略FORMAT = "DEFAULT",因为DEFAULT是默认格式,返回优化后的执行计划。
查看嵌套视图执行计划¶
EXPLAIN FORMAT = "DEFAULT" USE movie MATCH (a:Person)-[e]->(b@Movie) LIMIT 1 RETURN b
返回:
• Limit
│ details: Offset:0, Limit:1, Partial:false, Approx
│ :false
│
└── • HashJoin(Inner)(DF:/_id)
│ details: Project: b, element_id(b)=_right_node_i
│ d(e)
│
├── • [S]NodesScan
│ details: TableScan: {Movie: {name, id}}, b{}
│
└── • [S]Filter
│ details: in(node_type_id(_left_node_id(e)), [1024
│ ,1025,1026])
│
└── • [S]EdgesScan
details: direction: outgoing: true, incoming: fal
se, undirected0: false, undirected1: fal
se, TableScan: {Watch: {}}, TableScan: {
Direct: {}}, TableScan: {Act: {}}, e{}
Execution Plan: [Px] means pipeline-x and [S] means storage side.
Elapsed Time:
parse time : 624 us
build time : 951 us
optimize time : 929 us
serialize time: 41 us
total time : 3070 us
嵌套视图的每一层都对应一个算子,嵌套视图层级间的缩进表示算子间的依赖关系。例如,算子Limit依赖于HashJoin。
查看表格视图执行计划¶
若使用 ngql 命令行工具,可通过:planstyle命令将执行计划展示为表格形式。更多信息,请参见 ngql 的设置执行计划展示视图。
:planstyle table
EXPLAIN FORMAT = "DEFAULT" USE movie MATCH (a:Person)-[e]->(b@Movie) LIMIT 1 RETURN b
返回:
+----------------------------+------------------------------------------------------------------------------------------------------+
| plan | details |
+----------------------------+------------------------------------------------------------------------------------------------------+
| Limit | Offset:0, Limit:1, Partial:false, Approx:false |
| └─HashJoin(Inner)(DF:/_id) | Project: b, element_id(b)=_right_node_id(e) |
| ├─[S]NodesScan | TableScan: {Movie: {name, id}}, b{} |
| └─[S]Filter | in(node_type_id(_left_node_id(e)), [1024,1025,1026]) |
| └─[S]EdgesScan | direction: outgoing: true, incoming: false, undirected0: false, undirected1: false, TableScan: {W... |
+----------------------------+------------------------------------------------------------------------------------------------------+
Execution Plan: [Px] means pipeline-x and [S] means storage side.
Elapsed Time:
parse time : 269 us
build time : 314 us
optimize time : 350 us
serialize time: 61 us
total time : 1272 us
表中的每一行都对应一个算子,列plan中的缩进表示算子之间的依赖关系。例如,算子Limit依赖于HashJoin。
查看盒状视图执行计划¶
若使用 ngql 命令行工具,可通过:planstyle命令将执行计划展示为盒状视图。更多信息,请参见 ngql 的设置执行计划展示视图。
:planstyle box
EXPLAIN FORMAT = "DEFAULT" USE movie MATCH (a:Person)-[e]->(b@Movie) LIMIT 1 RETURN b
返回:
┌──────────────────────────────────────┐
│ Limit │
│ -------------------------------- │
│ Offset:0, Limit:1, Partial:false │
│ , Approx:false │
└──────────────────┬───────────────────┘
┌──────────────────┴───────────────────┐
│ HashJoin(Inner)(DF:/_id) │
│ -------------------------------- │
│ Project: b, element_id(b)=_righ │────────────────────┐
│ t_node_id(e) │ │
└──────────────────┬───────────────────┘ │
┌──────────────────┴───────────────────┐ ┌──────────────────┴───────────────────┐
│ [S]NodesScan │ │ [S]Filter │
│ -------------------------------- │ │ -------------------------------- │
│ TableScan: {Movie: {name, id}}, │ │ in(node_type_id(_left_node_id(e) │
│ b{} │ │ ), [1024,1025,1026]) │
└──────────────────────────────────────┘ └──────────────────┬───────────────────┘
┌──────────────────┴───────────────────┐
│ [S]EdgesScan │
│ -------------------------------- │
│ direction: outgoing: true, incom │
│ ing: false, undirected0: false, │
│ undirected1: false, TableScan: { │
│ Direct: {}}, TableScan: {Watch: │
│ {}}, TableScan: {Act: {}}, e{} │
└──────────────────────────────────────┘
Execution Plan: [Px] means pipeline-x and [S] means storage side.
Elapsed Time:
parse time : 820 us
build time : 1154 us
optimize time : 1116 us
serialize time: 92 us
total time : 3963 us
每个方框代表一个算子,方框之间的连接表示上方算子依赖于下方算子的输出。例如,算子Limit依赖于HashJoin。
指定RAW查看未优化的逻辑计划¶
EXPLAIN RAW USE movie MATCH (a:Person)-[e]->(b@Movie) LIMIT 1 RETURN b
上述示例指定选项RAW,返回查询MATCH (a:Person)-[e]->(b@Movie) LIMIT 1 RETURN b的未优化逻辑计划。
返回:
• Project
│ details: b
│
└── • Limit
│ details: Offset:0, Limit:1, Partial:false, Approx
│ :false
│
└── • LogicalJoin(Cross)
│
├── • Values(UNIT)
│ details: UNIT
│
└── • Project
│ details: b, e, a
│
└── • LogicalJoin(Inner)
│ details: element_id(b)=_right_node_id(e)
│
├── • GetNodes
│ details: Movie,, b{_GraphId,_id,id,name}
│
└── • LogicalJoin(Inner)
│ details: _left_node_id(e)=element_id(a)
│
├── • [S]GetEdges
│ details: Act,Direct,Watch,, e{rate}
│
└── • GetNodes
details: Actor,Director,User,, a{_GraphId,_id,bir
thDate,id,name}
Execution Plan: [Px] means pipeline-x and [S] means storage side.
Elapsed Time:
parse time : 173 us
build time : 0 us
optimize time : 0 us
serialize time: 25 us
total time : 582 us
嵌套视图的每一层都对应一个算子,嵌套视图层级间的缩进表示算子间的依赖关系。
指定DECORRELATED查看解关联后的逻辑计划¶
EXPLAIN DECORRELATED返回经过子查询解关联处理后的执行计划,展示关联子查询被改写为等价非关联形式后的逻辑计划。
'''
EXPLAIN DECORRELATED
USE movie MATCH (a@Actor)
WHERE EXISTS {USE movie MATCH (v@Actor) RETURN v}
RETURN a.name
LIMIT 5
'''
返回:
• Project
│ details: a.name
│
└── • Limit
│ details: Offset:0, Limit:5, Partial:false, Approx
│ :false
│
└── • LogicalJoin(Cross)
│
├── • GetNodes
│ details: Actor,, a{_GraphId,_id,birthDate,id,name
│ }
│
└── • Project
│ details: CASE WHEN @anon2 = 1 THEN true ELSE fals
│ e END AS @anon2
│
└── • Filter
│ details: CASE WHEN @anon2 = 1 THEN true ELSE fals
│ e END
│
└── • Aggregate
│ details: Partial: false, Single: true, Memory: tr
│ ue, AGGREGATE count(true) AS @anon2
│
└── • Project
│ details: v
│
└── • Limit
│ details: Offset:0, Limit:1, Partial:false, Approx
│ :false
│
└── • LogicalJoin(Cross)
│
├── • Values(UNIT)
│ details: UNIT
│
└── • GetNodes
details: Actor,, v{_GraphId,_id,birthDate,id,name
}
Execution Plan: [Px] means pipeline-x and [S] means storage side.
Elapsed Time:
parse time : 497 us
build time : 572 us
optimize time : 614 us
serialize time: 55 us
total time : 2147 us
Note
DECORRELATED阶段主要对包含关联子查询的查询有显著效果。对于不包含子查询的查询,DECORRELATED阶段的输出与RAW阶段的输出可能相同或差异很小。
指定CBO查看 CBO 重排序后的逻辑计划¶
EXPLAIN CBO返回经过基于代价的优化器(Cost-Based Optimizer,CBO)阶段处理后的执行计划,展示该阶段完成后、最终计划生成之前的逻辑计划。若需在输出中观察MATCH模式展开顺序重排的效果,需要显式开启enable_reorder。
'''
EXPLAIN CBO /*+ SET_VAR(enable_reorder=true) */
USE movie MATCH (a:Person)-[e]->(b@Movie) LIMIT 1 RETURN b
'''
返回:
• Limit
│ details: Offset:0, Limit:1, Partial:false, Approx
│ :false
│
└── • Project
│ details: b
│
└── • Extend
│ details: Emit: from=true, edge=true, to=true, Dir
│ ection: outgoing: false, incoming: true,
│ undirected0: false, undirected1: false,
│ ToNode: a, EdgeField: e, FromNode: b, M
│ ode: All, Graph: movie(1024)
│
└── • GetNodes
details: Movie,, b{_GraphId,_id,id,name}
Execution Plan: [Px] means pipeline-x and [S] means storage side.
Elapsed Time:
parse time : 860 us
build time : 812 us
optimize time : 708 us
serialize time: 38 us
total time : 2987 us
Note
并非所有查询都会经过 CBO 阶段。EXPLAIN CBO仅在满足条件的图模式/Join 重排场景下输出与默认计划不同的结果。对于不涉及 CBO 优化的查询,其输出可能与DECORRELATED阶段相同。
enable_reorder默认值为false。如果需要将重排后的MATCH计划与默认的文本顺序计划进行对比,请在查询级、会话级或全局级显式开启该配置。
若 CBO 重排序后的计划与预期不符,或想了解 CBO 选择特定计划的原因,可以启用enable_cbo_trace=true并检查nebula-graphd.INFO日志。
enable_cbo_trace是会话级配置项,其默认值为false。
例如:
'''
EXPLAIN /*+ set_var(enable_cbo_trace=true) */
USE movie MATCH (a:Person)-[e]->(b@Movie) LIMIT 1 RETURN b
'''
若 CBO 优化器选择了特定计划,nebula-graphd.INFO日志中打印如下信息:
I20260326 14:45:11.947098 1439136 CboTrace.cpp:31] [CBO] ===== Trace Summary =====
Pattern: nodes=2, edges=1, predicates=0
Leaf Plans
...
[CBO] ===== End Trace Summary =====
指定选项FORMAT = "VERBOSE"查看详细优化的执行计划¶
EXPLAIN FORMAT = "VERBOSE" USE movie MATCH (a:Person)-[e]->(b@Movie) LIMIT 1 RETURN b
上述示例通过指定选项FORMAT = "VERBOSE",以详细格式显示查询USE movie MATCH (a:Person)-[e]->(b@Movie) LIMIT 1 RETURN b的优化执行计划。
返回:
• Limit
│ details: Offset:0, Limit:1, Partial:false, Approx
│ :false
│ columns: [b]
│
└── • HashJoin(Inner)(DF:/_id)
│ details: Project: b:NodeRef<(Movie)>, element_id
│ (b::NodeRef<(Movie)>)::INT64=(_right_nod
│ e_id(e::EdgeRef<(Actor)-[Act]->(Movie),
│ (Director)-[Direct]->(Movie), (User)-[Wa
│ tch]->(Movie)>))::INT64
│ columns: [b]
│
├── • [S]NodesScan
│ details: TableScan: {Movie: {name, id}}, b{}
│ columns: [b]
│
└── • [S]Filter
│ details: (in((node_type_id((_left_node_id(e::Edge
│ Ref<(Actor)-[Act]->(Movie), (Director)-[
│ Direct]->(Movie), (User)-[Watch]->(Movie
│ )>))::INT64))::INT16, [1024,1025,1026]::
│ LIST<INT16>))::BOOL
│ columns: [e]
│
└── • [S]EdgesScan
details: direction: outgoing: true, incoming: fal
se, undirected0: false, undirected1: fal
se, TableScan: {Watch: {}}, TableScan: {
Direct: {}}, TableScan: {Act: {}}, e{}
columns: [e]
Execution Plan: [Px] means pipeline-x and [S] means storage side.
Elapsed Time:
parse time : 234 us
build time : 258 us
optimize time : 387 us
serialize time: 39 us
total time : 1184 us
嵌套视图的每一层都对应一个算子,嵌套视图层级间的缩进表示算子间的依赖关系。例如,算子Limit依赖于HashJoin。
指定RAW和FORMAT = "VERBOSE"查看未优化的详细逻辑计划¶
EXPLAIN RAW FORMAT = "VERBOSE" USE movie MATCH (a:Person)-[e]->(b@Movie) LIMIT 1 RETURN b
返回:
• Project
│ details: b::NodeRef<(Movie)>
│ columns: [b]
│
└── • Limit
│ details: Offset:0, Limit:1, Partial:false, Approx
│ :false
│ columns: [b, e, a]
│
└── • LogicalJoin(Cross)
│ columns: [b, e, a]
│
├── • Values(UNIT)
│ details: UNIT
│ columns: []
│
└── • Project
│ details: b::NodeRef<(Movie)>, e::EdgeRef<(Actor)-
│ [Act]->(Movie), (Director)-[Direct]->(Mo
│ vie), (User)-[Watch]->(Movie)>, a::NodeR
│ ef<(Actor), (Director), (User)>
│ columns: [b, e, a]
│
└── • LogicalJoin(Inner)
│ details: element_id(b::NodeRef<(Movie)>)::INT64=(
│ _right_node_id(e::EdgeRef<(Actor)-[Act]-
│ >(Movie), (Director)-[Direct]->(Movie),
│ (User)-[Watch]->(Movie)>))::INT64
│ columns: [b, e, a]
│
├── • GetNodes
│ details: Movie,, b{_GraphId,_id,id,name}
│ columns: [b]
│
└── • LogicalJoin(Inner)
│ details: (_left_node_id(e::EdgeRef<(Actor)-[Act]-
│ >(Movie), (Director)-[Direct]->(Movie),
│ (User)-[Watch]->(Movie)>))::INT64=(eleme
│ nt_id(a::NodeRef<(Actor), (Director), (U
│ ser)>))::INT64
│ columns: [e, a]
│
├── • [S]GetEdges
│ details: Act,Direct,Watch,, e{rate}
│ columns: [e]
│
└── • GetNodes
details: Actor,Director,User,, a{_GraphId,_id,bir
thDate,id,name}
columns: [a]
Execution Plan: [Px] means pipeline-x and [S] means storage side.
Elapsed Time:
parse time : 281 us
build time : 0 us
optimize time : 0 us
serialize time: 39 us
total time : 775 us
嵌套视图的每一层都对应一个算子,嵌套视图层级间的缩进表示算子间的依赖关系。