探索查询执行摘要
在查询结果的所有记录都被处理完之后,服务器通过返回执行摘要来结束事务。它以一个 ResultSummary 对象的形式出现,并且其中包含以下信息
检索执行摘要
使用 Driver.executeQuery() 运行查询时,执行摘要作为默认返回值的第二个对象返回。
let { records, summary } = await driver.executeQuery(`
UNWIND ['Alice', 'Bob'] AS name
MERGE (p:Person {name: name})
`, {},
{ database: '<database-name>' }
)
// or summary = (await driver.executeQuery('<QUERY>')).summary
如果你正在使用 事务函数,可以通过属性 Result.summary(在使用 await 解析结果 Promise 时)或方法 Result.summary()(在将结果作为 Promise 消耗时)获取查询执行摘要。
请注意,一旦请求执行摘要,结果流将被耗尽:任何尚未处理的记录将不再可用。
let session = driver.session({ database: '<database-name>' })
try {
let summary = await session.executeWrite(async tx => {
let result = await tx.run(`
UNWIND ['Alice', 'Bob'] AS name
MERGE (p:Person {name: name})
`)
return result.summary
// or result.summary(), if you don't await tx.run()
})
} finally {
session.close()
}
查询计数器
属性 ResultSummary.counters 包含查询触发的操作计数(以 QueryStatistics 对象的形式)。
let { records, summary } = await driver.executeQuery(`
UNWIND ['Alice', 'Bob'] AS name
MERGE (p:Person {name: name})
`, {},
{ database: '<database-name>' }
)
console.log(summary.counters.updates())
/*
{
nodesCreated: 2,
nodesDeleted: 0,
relationshipsCreated: 0,
relationshipsDeleted: 0,
propertiesSet: 0,
labelsAdded: 1,
labelsRemoved: 0,
indexesAdded: 0,
indexesRemoved: 0,
constraintsAdded: 0,
constraintsRemoved: 0
}
*/
console.log(summary.counters.containsUpdates()) // true
console.log(summary.counters.containsSystemUpdates()) // false
ResultSummary.counters 上的两个额外方法充当元计数器
-
.containsUpdates()— 查询是否在其运行的数据库上触发了任何写操作 -
.containsSystemUpdates()— 查询是否在system数据库上触发了任何写操作
查询执行计划
如果在查询前加上 EXPLAIN,服务器会返回它*本将在运行查询时使用的*执行计划,但并不真正执行查询。该计划随后以 Plan 对象的形式出现在属性 ResultSummary.plan 中,并包含用于检索结果集的 Cypher 操作符 列表。利用这些信息可以定位瓶颈或潜在的性能改进(例如通过创建索引)。
let result = await driver.executeQuery('EXPLAIN MATCH (p {name: $name}) RETURN p', { name: 'Alice' })
console.log(result.summary.plan.arguments['string-representation'])
/*
Planner COST
Runtime PIPELINED
Runtime version 5.0
Batch size 128
+-----------------+----------------+----------------+---------------------+
| Operator | Details | Estimated Rows | Pipeline |
+-----------------+----------------+----------------+---------------------+
| +ProduceResults | p | 1 | |
| | +----------------+----------------+ |
| +Filter | p.name = $name | 1 | |
| | +----------------+----------------+ |
| +AllNodesScan | p | 10 | Fused in Pipeline 0 |
+-----------------+----------------+----------------+---------------------+
Total database accesses: ?
*/
如果改为在查询前加上关键字 PROFILE,服务器会返回实际运行查询时使用的执行计划以及分析器统计信息。这包括所使用的操作符列表以及每一步的额外分析信息。该计划可通过属性 ResultSummary.profile 获取。请注意,查询会真正被执行,因此结果对象仍然包含所有结果记录。
let result = await driver.executeQuery('PROFILE MATCH (p {name: $name}) RETURN p', { name: 'Alice' })
console.log(result.summary.profile.arguments['string-representation'])
/*
Planner COST
Runtime PIPELINED
Runtime version 5.0
Batch size 128
+-----------------+----------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+
| Operator | Details | Estimated Rows | Rows | DB Hits | Memory (Bytes) | Page Cache Hits/Misses | Time (ms) | Pipeline |
+-----------------+----------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+
| +ProduceResults | p | 1 | 1 | 3 | | | | |
| | +----------------+----------------+------+---------+----------------+ | | |
| +Filter | p.name = $name | 1 | 1 | 4 | | | | |
| | +----------------+----------------+------+---------+----------------+ | | |
| +AllNodesScan | p | 10 | 4 | 5 | 120 | 9160/0 | 108.923 | Fused in Pipeline 0 |
+-----------------+----------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+
Total database accesses: 12, total allocated memory: 184
*/
有关更多信息和示例,请参见 基本查询调优。
通知
执行查询后,服务器可以在查询结果旁返回通知。通知包括性能改进建议、关于使用已弃用特性的警告以及其他关于 Neo4j 使用不佳的提示。
属性 ResultSummary.gqlStatusObjects 包含一系列 GqlStatusObject。这些是符合 GQL 标准的状态对象。
部分(但不是全部)GqlStatusObjects 是通知,而另一些则报告结果状态:00000 表示“成功”,02000 表示“无数据”,以及 00001 表示“省略的结果”。Summary.GqlStatusObjects() 始终至少包含一条记录,即结果状态。
let { records, summary } = await driver.executeQuery(`
MATCH p=shortestPath((:Person {name: 'Alice'})-[*]->(:Person {name: 'Bob'}))
RETURN p
`, {},
{ database: '<database-name>' }
)
console.log(summary.gqlStatusObjects)
/*
[
GqlStatusObject {
gqlStatus: '02000',
statusDescription: 'note: no data',
diagnosticRecord: { OPERATION: '', OPERATION_CODE: '0', CURRENT_SCHEMA: '/' },
position: undefined,
severity: 'UNKNOWN',
rawSeverity: undefined,
classification: 'UNKNOWN',
rawClassification: undefined,
isNotification: false
},
GqlStatusObject {
gqlStatus: '03N91',
statusDescription: "info: unbounded variable length pattern. The provided pattern `(:Person {name: 'Alice'})-[*]->(:Person {name: 'Bob'})` is unbounded. Shortest path with an unbounded pattern may result in long execution times. Use an upper limit (e.g. `[*..5]`) on the number of node hops in your pattern.",
diagnosticRecord: {
OPERATION: '',
OPERATION_CODE: '0',
CURRENT_SCHEMA: '/',
_classification: 'PERFORMANCE',
_status_parameters: [Object],
_severity: 'INFORMATION',
_position: [Object]
},
position: { offset: 24, line: 2, column: 24 },
severity: 'INFORMATION',
rawSeverity: 'INFORMATION',
classification: 'PERFORMANCE',
rawClassification: 'PERFORMANCE',
isNotification: true
}
]
*/
在 6.0 中已弃用
属性 ResultSummary.notifications 包含一系列 Notification 对象。
let { records, summary } = await driver.executeQuery(`
MATCH p=shortestPath((:Person {name: 'Alice'})-[*]->(:Person {name: 'Bob'}))
RETURN p
`, {},
{ database: '<database-name>' }
)
console.log(summary.notifications)
/*
[
Notification {
code: 'Neo.ClientNotification.Statement.UnboundedVariableLengthPattern',
title: 'The provided pattern is unbounded, consider adding an upper limit to the number of node hops.',
description: 'Using shortest path with an unbounded pattern will likely result in long execution times. It is recommended to use an upper limit to the number of node hops in your pattern.',
severity: 'INFORMATION',
position: { offset: 24, line: 2, column: 22 },
severityLevel: 'INFORMATION',
rawSeverityLevel: 'INFORMATION',
category: 'PERFORMANCE',
rawCategory: 'PERFORMANCE'
}
]
*/
过滤通知
默认情况下,服务器会对每个查询的所有通知类别和严重程度进行分析。使用参数 minimumSeverityLevel 和/或 disabledCategories/disabledClassifications 可限制感兴趣的通知的严重程度和/或类别/分类。限制服务器可产生的通知数量可以略微提升性能。这些参数既可以在创建 Driver 实例时使用,也可以在创建会话时使用。
严重程度过滤器同时适用于 Neo4j 和 GQL 的通知。类别和分类过滤器之所以分开,仅是因为 GQL 与 Neo4j 在词汇上的差异;不过这两类过滤器都会影响所有形式的通知,因此应仅使用其中之一。自 6.0 版本起,disabledCategories 已被弃用。
将最低严重程度设为 'OFF' 可完全禁用通知。
WARNING 通知,且不包括 HINT 或 GENERIC 分类的通知// at driver level
let driver = neo4j.driver(
URI, neo4j.auth.basic(USER, PASSWORD), {
notificationsFilter: {
minimumSeverityLevel: 'WARNING', // or 'OFF' to disable entirely
disabledClassifications: ['HINT', 'GENERIC'] // filters categories as well
}
}
)
// at session level
let session = driver.session({
database: '<database-name>',
notificationsFilter: {
minimumSeverityLevel: 'WARNING', // or 'OFF' to disable entirely
disabledClassifications: ['HINT', 'GENERIC'] // filters categories as well
}
})