这些密码查询有什么区别?

时间:2014-04-30 14:24:17

标签: neo4j cypher

这些查询在逻辑上等效,返回相同的6个结果(除了最后只返回5个结果),但性能差异很大,从31毫秒到45秒不等。我使用的是Neo4j 2.0.2。我有一个索引ON:SEGMENT(propertyId),但查找(n)不是查询速度慢的原因。

match (n {productId:6122})<-[:PARENT_OF*]-(p) return n,p;
[...]
6 rows
43879 ms

match (n:SEGMENT {productId:6122})<-[:PARENT_OF*]-(p) return n,p;
[...]
6 rows
44926 ms

start n=node(111426) match (n)<-[:PARENT_OF*]-(p) return n,p;
[...]
6 rows
31 ms

match (n {productId:6122}) match path=(n)<-[:PARENT_OF*]-(p) return path;
[...]
6 rows
694 ms

match (n:SEGMENT {productId:6122}) match path=(n)<-[:PARENT_OF*]-(p) return path;
[...]
6 rows
161 ms

match (n:SEGMENT)<-[:PARENT_OF*]-(p:SEGMENT) where n.productId=6122 return n,p;
[...]
5 rows
45332 ms

添加了PROFILE输出:

PROFILE match (n:SEGMENT {productId:6122})<-[:PARENT_OF*]-(p:SEGMENT) return n,p;
`ColumnFilter(symKeys=["n", "p", "  UNNAMED34"], returnItemNames=["n", "p"], _rows=5, _db_hits=0)
Filter(pred="(hasLabel(n:SEGMENT(0)) AND Property(n,productId(9)) == Literal(6122))", _rows=5, _db_hits=1895169)
  TraversalMatcher(start={"label": "SEGMENT", "producer": "NodeByLabel", "identifiers": ["p"]}, trail="(p)-[:PARENT_OF*1..]->(n)", _rows=1895169, _db_hits=1895169)`

PROFILE match (n {productId:6122}) match path=(n)<-[:PARENT_OF*]-(p) return path; 
`ColumnFilter(symKeys=["n", "p", "  UNNAMED41", "path"], returnItemNames=["path"], _rows=6, _db_hits=0)
ExtractPath(name="path", patterns=["ParsedVarLengthRelation(  UNNAMED41,Map(),ParsedEntity(n,n,Map(),List()),ParsedEntity(p,p,Map(),List()),List(PARENT_OF),INCOMING,false,None,None,None)"], _rows=6, _db_hits=0)
  PatternMatcher(g="(n)-['  UNNAMED41']-(p)", _rows=6, _db_hits=0)
    Filter(pred="Property(n,productId(9)) == Literal(6122)", _rows=1, _db_hits=48531)
      AllNodes(identifier="n", _db_hits=48531, _rows=48531, identifiers=["n"], producer="AllNodes")`

1 个答案:

答案 0 :(得分:2)

最快的查询是内部ID查找,这并不奇怪。 ID值本身(避免将其作为外部标识符)与存储的数据结构紧密耦合。它大致相当于告诉Cypher节点在节点存储文件中的位置。 (*)

对于接下来的两个最快的,我可能完全错误,但我认为它们更快,因为你只匹配路径,虽然我不确定这究竟是如何影响查询的行为。 两者之间的小增量可以通过以下事实来解释:一个查询在引擎盖下使用模式索引,而另一个不是(因为标签在第二种情况下未指定)。

对于最后3个,可能与起点PARENT_OF的深度相比,起点位置查找时间非常无关紧要。你最终可能会走很长的路,我不确定。

(*)我仍然不明白如何通过起始节点的ID来查找与类似的2个最慢查询(它们也不会通过路径匹配......)的差异。