我有以下Cypher查询
MATCH (p1:`Article` {article_id:'1234'})--(a1:`Author` {name:'Jones, P'})
MATCH (p2:`Article` {article_id:'5678'})--(a2:`Author` {name:'Jones, P'})
MATCH (p1)-[:WRITTEN_BY]->(c1:`Author`)-[h1:HAS_NAME]->(l1)
MATCH (p2)-[:WRITTEN_BY]->(c2:`Author`)-[h2:HAS_NAME]->(l2)
WHERE l1=l2 AND c1<>a1 AND c2<>a2
RETURN c1.FullName, c2.FullName, h1.distance + h2.distance
在我的本地Neo4j服务器上,运行此查询需要大约4秒钟,PROFILE
显示大约300万分贝命中。如果我没有在Author
和c1
上指定c2
标签(由于关系标签,它是多余的),相同的查询会在33毫秒内返回相同的输出,{{1} }显示&lt; 200 db hits。
当我在远程服务器上托管的同一数据库的较大版本上运行相同的两个查询时,这种性能差异就会消失。
两个dbs都有相同的约束和索引。有什么想法可能会出错?
答案 0 :(得分:2)
你的查询中有很多不必要的东西,所以首先,这是一个更清晰的版本,不太可能被计划者误解:
MATCH (name:Name) WHERE NOT name.name = 'Jones, P'
WITH name
MATCH (:`Article` {article_id:'1234'})-[:WRITTEN_BY]->()-[h1:HAS_NAME]->(name)<-[h2:HAS_NAME]-()<-[:WRITTEN_BY]-(:`Article` {article_id:'5678'})
RETURN name.name, h1.distance + h2.distance
您确实只想找到一个路径,并且您希望为名称不是Jones, P
的任何作者找到它。利用您的共享:Name
节点,使用最小的一组确定点开始查询,并从那里扩展路径。您通过堆叠所有MATCH
语句然后将其过滤掉来生成大量笛卡尔积。
至于查询性能的差异,似乎查询规划器正在尝试使用Author
标签来构建您的第3和第4条路径,而如果您将其遗漏,则规划器只会触及很多较窄的:Article
s集合(由索引属性修复),然后通过(偶然非常小的)具有-[:WRITTEN_BY]->
关系的节点集合扩展关系,然后是那些(通常非常小的)一组节点具有-[:HAS_NAME]->
关系的节点。该决定部分基于各种集合的可预测大小,因此如果服务器上有不同数量的:Author
节点,则规划人员将做出更明智的选择而不使用它们。