neo4j 密码DELETE关系比编程关系::delete慢得多

bksxznpy  于 2023-05-06  发布在  其他
关注(0)|答案(1)|浏览(210)

我的数据模型

(:Parent {parentId:...})-[:CONTAINS]->(:Child)-[:SUPPORTS]->(:Dummy)

每个Child只有一个ParentParent.parentId属性是唯一的,即有一个约束定义为

CREATE CONSTRAINT Parent_parentId_unique IF NOT EXISTS ON (p:Parent) ASSERT p.parentId IS UNIQUE;

我有一个用户定义的@Procedure,它接受parentIds的集合,我想从它们的所有子对象中删除所有:SUPPORTS关系。

  • 当一切都是加密的时候,过程的执行是缓慢的--几百毫秒到几秒。
Result removeRelationshipResult = tx.execute(""
        + "MATCH (p:Parent)-[:CONTAINS]->(c:Child)-[r:SUPPORTS]->(:Dummy)\n"
        + "WHERE p.parentId IN $parentIds\n"
        + "DELETE r",
        Map.of("parentIds", parentIds)
);
RelationshipType CONTAINS = RelationshipType.withName("CONTAINS");
RelationshipType SUPPORTS = RelationshipType.withName("SUPPORTS");
for (Long parentId : parentIds) {
    Node parentNode = tx.findNode(Parent.LABEL, "parentId", parentId);
    streamOf(parentNode.getRelationships(Direction.OUTGOING, CONTAINS))
        .map(rel -> rel.getEndNode())
        .flatMap(childNode -> streamOf(childNode.getRelationships(SUPPORTS)))
        .forEach(Relationship::delete);
}

即使在没有:SUPPORTS关系的情况下,第一次尝试也会出现差异。
造成这种差异的原因是什么?如何发现它?

**更新:**对@cybersam的回答的React(太长,无法评论):

我在样本上测试了你的建议,使用了1737个Parent节点和655344个:SUPPORTS关系,分成61个批次(用于从第2点开始的预热,尽管拆分的主要目的不同)。
应用点#1导致了巨大的性能改进。现在的时间与方案执行时间相当。我还试图改变程序实现,反之亦然,即。添加过滤到节点标签,但没有显著效果。实际上,第一次运行(当不存在关系时)和第二次运行(当实际删除第一次运行的关系时)的时间比较不同。第三次和下一次运行与第二次运行相似。第1点清楚地回答了我的问题,并帮助了我很多,谢谢!
| 实施|首次运行:删除时间/总手术时间|第二次运行:删除时间/总手术时间[ms]|
| --------------|--------------|--------------|
| 密码标记|79366/131261|170283/188783|
| 密码非标记|230/13756|1800/17284|
| 程序标签|155/11731|2235/19539|
| 程序无标签|174/11805|2079/19111|

3htmauhk

3htmauhk1#

造成速度差异的原因至少有三个。
1.您的Cypher查询指定SUPPORT关系的起始节点必须是Child,其结束节点必须是Dummy。您的Java代码不关心这两个节点有什么标签,因此必须做更少的工作。这个替代的MATCH子句更等效:

MATCH (p:Parent)-[:CONTAINS]->()-[r:SUPPORTS]->()

1.当第一次执行Cypher查询时(或者在从Cypher查询缓存中删除后再次执行),必须解析、检查错误并转换为基于DB的当前特征进行优化的Java操作--所有这些都需要时间。一旦Cypher查询的操作被缓存,相同的Cypher查询将运行得更快。因此,更公平的比较要求您多次运行Cypher查询,并忽略第一次运行的时间。
1.与生成代码的情况一样,您不能期望从Cypher查询生成的Java代码总是与尝试做同样事情的手工代码一样高效。一些额外的开销是正常的。

相关问题