探索查询执行摘要
在从查询中返回的所有结果都已处理后,服务器通过返回执行摘要来结束事务。它以 ResultSummary
对象的形式出现,其中包含以下信息
检索执行摘要
当使用 Driver.executableQuery()
运行查询时,执行摘要是默认返回对象的一部分,可以通过 .summary()
方法检索。
var result = driver.executableQuery("""
UNWIND ['Alice', 'Bob'] AS name
MERGE (p:Person {name: name})
""")
.withConfig(QueryConfig.builder().withDatabase("neo4j").build())
.execute();
var resultSummary = result.summary();
如果您使用的是 事务函数,则可以使用 Result.consume()
方法检索查询执行摘要。注意,一旦您请求执行摘要,结果流就会被耗尽。这意味着任何尚未处理的记录都会被丢弃。
try (var session = driver.session(SessionConfig.builder().withDatabase("neo4j").build())) {
var resultSummary = session.executeWrite(tx -> {
var result = tx.run("""
UNWIND ['Alice', 'Bob'] AS name
MERGE (p:Person {name: name})
""");
return result.consume();
});
}
查询计数器
ResultSummary.counters()
方法返回查询触发的操作的计数器(作为 SummaryCounters
对象)。
var result = driver.executableQuery("""
MERGE (p:Person {name: $name})
MERGE (p)-[:KNOWS]->(:Person {name: $friend})
""").withParameters(Map.of("name", "Mark", "friend", "Bob"))
.withConfig(QueryConfig.builder().withDatabase("neo4j").build())
.execute();
var queryCounters = result.summary().counters();
System.out.println(queryCounters);
/*
InternalSummaryCounters{nodesCreated=2, nodesDeleted=0, relationshipsCreated=1, relationshipsDeleted=0,
propertiesSet=2, labelsAdded=2, labelsRemoved=0, indexesAdded=0, indexesRemoved=0, constraintsAdded=0,
constraintsRemoved=0, systemUpdates=0}
*/
还有两个额外的布尔方法充当元计数器
-
.containsUpdates()
— 查询是否在它运行的数据库上触发了任何写入操作 -
.containsSystemUpdates()
— 查询是否更新了system
数据库
查询执行计划
如果在查询前面加上 EXPLAIN
,服务器将返回它将用来运行查询的计划,但不会实际运行它。该计划然后作为 Plan
对象通过 ResultSummary.plan()
方法提供,其中包含将用于检索结果集的 Cypher 运算符 列表。您可以使用此信息来定位潜在的瓶颈或 性能改进 的空间(例如通过创建索引)。
var result = driver.executableQuery("EXPLAIN MATCH (p {name: $name}) RETURN p")
.withParameters(Map.of("name", "Alice"))
.withConfig(QueryConfig.builder().withDatabase("neo4j").build())
.execute();
var queryPlan = result.summary().plan().arguments().get("string-representation");
System.out.println(queryPlan);
/*
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
,服务器将返回它用来运行查询的执行计划,以及探查器统计信息。这包括使用的运算符列表以及有关每个中间步骤的额外探查信息。该计划作为 Plan
对象通过 ResultSummary.profile()
方法提供。请注意,查询也被运行,因此结果对象还包含任何结果记录。
var result = driver.executableQuery("PROFILE MATCH (p {name: $name}) RETURN p")
.withParameters(Map.of("name", "Alice"))
.withConfig(QueryConfig.builder().withDatabase("neo4j").build())
.execute();
var queryPlan = result.summary().profile().arguments().get("string-representation");
System.out.println(queryPlan);
/*
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 的其他提示。
对于驱动程序版本>= 5.25 和服务器版本>= 5.23,两种形式的通知可用(Neo4j 状态码和GQL 状态码)。对于早期版本,仅提供Neo4j 状态码。 计划用 GQL 状态码取代 Neo4j 状态码。 |
ResultSummary.notifications()
方法返回 Notification
对象列表。
var result = driver.executableQuery("""
MATCH p=shortestPath((:Person {name: $start})-[*]->(:Person {name: $end}))
RETURN p
""")
.withParameters(Map.of("start", "Alice", "end", "Bob"))
.withConfig(QueryConfig.builder().withDatabase("neo4j").build())
.execute();
var notifications = result.summary().notifications();
System.out.println(notifications);
/*
[
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.,
severityLevel=InternalNotificationSeverity[type=INFORMATION,
level=800],
rawSeverityLevel=INFORMATION,
category=InternalNotificationCategory[type=PERFORMANCE],
rawCategory=PERFORMANCE,
position={offset=21, line=1, column=22}
]
*/
对于版本>= 5.25,ResultSummary.gqlStatusObjects()
方法返回一个有序的 GQL 兼容状态对象集。
该集合可以包含 Notification
对象和 GqlStatusObject
对象。后者对查询的结果状态进行编码:对于“成功”为 00000
,对于“无数据”为 02000
,对于“省略结果”为 00001
。该集合始终至少包含一个条目,其中包含结果状态。
var result = driver.executableQuery("""
MATCH p=shortestPath((:Person {name: $start})-[*]->(:Person {name: $end}))
RETURN p
""")
.withParameters(Map.of("start", "Alice", "end", "Bob"))
.withConfig(QueryConfig.builder().withDatabase("neo4j").build())
.execute();
var statuses = result.summary().gqlStatusObjects();
System.out.println(statuses);
/*
[
InternalGqlStatusObject{gqlStatus='02000', statusDescription='note: no data', diagnosticRecord={OPERATION_CODE="0", OPERATION="", CURRENT_SCHEMA="/"}},
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., severityLevel=InternalNotificationSeverity[type=INFORMATION, level=800], rawSeverityLevel=INFORMATION, classification=PERFORMANCE, rawClassification=PERFORMANCE, position={offset=21, line=1, column=22}
]
*/
筛选通知
默认情况下,服务器会针对所有类别和通知严重性分析每个查询。从版本 5.22 开始,您可以使用配置方法 .withMinimumNotificationSeverity()
和 .withDisabledNotificationClassification()
来调整您感兴趣的通知的严重性和/或类别/分类,或者完全禁用它们。限制服务器允许引发的通知数量会带来轻微的性能提升。
严重性过滤器适用于 Neo4j 和 GQL 通知。类别过滤器对类别和分类都有效。
您可以在创建 Driver
实例时在 Config
对象上调用这些方法,也可以在创建会话时在 SessionConfig
对象上调用这些方法。
WARNING
通知,但不允许 HINT
或 GENERIC
分类// import java.util.Set
// import org.neo4j.driver.Config;
// import org.neo4j.driver.NotificationClassification;
// import org.neo4j.driver.NotificationConfig;
// import org.neo4j.driver.NotificationSeverity;
// import org.neo4j.driver.SessionConfig;
// at `Driver` level
var driver = GraphDatabase.driver(
dbUri, AuthTokens.basic(dbUser, dbPassword),
Config.builder()
.withMinimumNotificationSeverity(NotificationSeverity.WARNING) // NotificationSeverity.OFF to disable entirely
.withDisabledNotificationClassifications(Set.of(NotificationClassification.PERFORMANCE, NotificationClassification.GENERIC)) // filters categories as well
.build()
);
// at `Session` level
var session = driver.session(
SessionConfig.builder()
.withDatabase("neo4j")
.withMinimumNotificationSeverity(NotificationSeverity.WARNING) // NotificationSeverity.OFF to disable entirely
.withDisabledNotificationClassifications(Set.of(NotificationClassification.PERFORMANCE, NotificationClassification.GENERIC)) // filters categories as well
.build()
);
在 5.22 之前版本的通知筛选
对于 5.22 之前的版本,通知筛选通过配置方法 .withNotificationConfig()
(5.7+ 版本)完成。
NotificationConfig
接口提供 .enableMinimumSeverity()
、.disableCategories()
和 .disableAllConfig()
方法来设置配置。
WARNING
通知,但不允许 HINT
或 GENERIC
类别// import java.util.Set
// import org.neo4j.driver.Config;
// import org.neo4j.driver.NotificationCategory;
// import org.neo4j.driver.NotificationConfig;
// import org.neo4j.driver.NotificationSeverity;
// import org.neo4j.driver.SessionConfig;
// at `Driver` level
var driver = GraphDatabase.driver(
dbUri, AuthTokens.basic(dbUser, dbPassword),
Config.builder()
.withNotificationConfig(NotificationConfig.defaultConfig()
.enableMinimumSeverity(NotificationSeverity.WARNING)
.disableCategories(Set.of(NotificationCategory.HINT, NotificationCategory.GENERIC))
).build()
);
// at `Session` level
var session = driver.session(
SessionConfig.builder()
.withDatabase("neo4j")
.withNotificationConfig(NotificationConfig.defaultConfig()
.enableMinimumSeverity(NotificationSeverity.WARNING)
.disableCategories(Set.of(NotificationCategory.HINT, NotificationCategory.GENERIC))
).build()
);
// import org.neo4j.driver.Config;
// import org.neo4j.driver.NotificationConfig;
// import org.neo4j.driver.SessionConfig;
// at `Driver` level
var driver = GraphDatabase.driver(
dbUri, AuthTokens.basic(dbUser, dbPassword),
Config.builder()
.withNotificationConfig(NotificationConfig.disableAllConfig())
.build()
);
// at `Session` level
var session = driver.session(
SessionConfig.builder()
.withDatabase("neo4j")
.withNotificationConfig(NotificationConfig.disableAllConfig())
.build()
);