跳转至
开发版采用单机部署,无需产品 License 文件。需要多机部署或大规模性能测试? 了解企业版

EXPLAIN

EXPLAIN命令显示查询的执行计划。与执行查询不同,EXPLAIN命令概述了查询执行期间采取的步骤,有利于调试和优化查询。

若使用 ngql 命令行工具,可通过:planstyle命令切换执行计划的展示形式(嵌套/表格/盒状)。默认风格为嵌套视图。更多信息,请参见 ngql 的设置执行计划展示视图。

优化管线

EXPLAIN命令支持查看查询在不同优化阶段的执行计划。完整的优化管线为:

  • RAW:优化前的原始逻辑计划。
  • DECORRELATED:子查询解关联后的逻辑计划。
  • CBO:CBO(基于代价的优化器)阶段后的逻辑计划。
  • 默认(不指定阶段):全部优化完成后的最终执行计划。

通过查看不同阶段的计划,可以定位优化过程中的具体问题,例如子查询改写是否生效、Join 顺序是否合理。

语法

explain_command
EXPLAIN RAW CBO DECORRELATED FORMAT = " VERBOSE DEFAULT " gql_query

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

嵌套视图的每一层都对应一个算子,嵌套视图层级间的缩进表示算子间的依赖关系。