为什么这两个看似相同的Cypher查询的速度差别很大?

时间:2017-08-17 18:26:11

标签: performance neo4j cypher

我有一个像这样的查询作为我的应用程序的关键组件:

MATCH (group:GroupType)
WHERE group.Name = "String"
MATCH (node:NodeType)
WHERE (node)-[:MEMBER_OF]->(group)
RETURN node

:GroupType(Name)

上有一个索引

在大约10,000个元素的数据库中,此查询使用近100万个数据库命中。以下是查询的PROFILE

Slow Query Profile

但是,执行相同搜索的查询的这种轻微变化要快得多:

MATCH (group:GroupType)
WHERE group.Name = "String"
MATCH (node:NodeType)-[:MEMBER_OF]->(group)
RETURN node

唯一的区别是node:NodeType匹配,并且关系匹配合并为单个MATCH而不是MATCH ... WHERE。尽管执行了相同的搜索,但此查询使用前一个查询的1/70数据库命中率并且速度提高了10倍以上:

Good Query Profile

我认为Cypher将MATCH ... WHERE语句视为单个搜索表达式,因此这两个查询应该编译为相同的操作,但这两个查询似乎执行了截然不同的操作。这是为什么?

2 个答案:

答案 0 :(得分:2)

首先我想说这实际上不是Cypher的问题。 Cypher描述了你想要的东西,而不是如何得到它,所以这个查询的性能将在Neo4J 3.1.1和Neo4J 3.2.3之间非常大。

由于执行Cypher的人是决定如何做到这一点的人,真正的问题是"为什么Neo4J Cypher计划者不会对这些做同样的处理?"

理想情况下,这两个Cyphers都应该等同于

MATCH (node:NodeType)-[:MEMBER_OF]->(group:GroupType{name:"String"})
RETURN node

因为它们都应该产生相同的结果。

实际上,动态解析具有非常多等同性的查询有很多微妙的细微差别。表达式。但是,如果你进行了这种调整,那么上下文中的微妙变化可以改变这种等同性

MATCH (group:GroupType)
WHERE group.Name = "String"
MATCH (node:NodeType)
WHERE (node)-[:MEMBER_OF]->(group) OR SIZE(group.members) = 1
RETURN node

现在两个查询的结果几乎没有任何相似之处。为了扩展,查询计划程序必须制定决策快捷方式,以便尽快制定有效的计划。

在排序中,性能取决于您正在运行的服务器正在运行,因为为某种语言提供了可操作的查找策略,可以让您要求任何事情/一切都很难!

相关阅读

答案 1 :(得分:0)

MATCH ... WHERE <pattern>MATCH <pattern>不同。

第一个查询执行匹配,然后使用模式作为过滤器来执行所有构建的行。

您可以在查询计划中看到正在发生的事情是您的第一个匹配结果与所有:NodeType节点之间的笛卡尔积。然后,对于笛卡尔积的每一行,WHERE检查以查看该行上的:GroupType节点是否通过给定模式连接到该行上的:NodeType节点(这是Expand(Into)操作)。

相比之下,第二个查询扩展了先前匹配的group节点的模式,因此从扩展中考虑的节点数量远远少于几乎立即相关,只需要最终过滤器以确保那些节点节点是:NodeType节点。

修改

正如Tezra指出的那样,Cypher通过让你定义你想要的东西,而不是如何得到它,因为规划师的工作“如何”。在当前版本的Neo4j(3.2.3)中,我的解释是,计划程序以不同方式解释每个查询并为每个查询生成不同的计划,但随着Cypher的发展和规划人员的改进,这可能会有所变化。

在这些情况下,您应该在查询上运行PROFILE并相应地进行调整。