2016-09-30 87 views
1

我对neo4j很新颖,而且我很难优化返回大量节点/关系的查询。Neo4j多个可选匹配查询非常慢

下面的查询:

MATCH (u:User)-[:CAN_ADMINISTER]->(cs:CustomerSite) 
WHERE u.id="1234" WITH cs 
MATCH r1=(cs)<-[:AFFECTS_SITE]-(t:Ticket) 
WHERE not(t.status = "COMPLETE") 
OPTIONAL MATCH r2=(t)-[:HAS_EVENTS]->(te:TicketEvent) 
OPTIONAL MATCH r3=(t)-[:CREATED_BY]->(u:User) 
OPTIONAL MATCH r4=(te)<-[:HAS_EVENTS]-(u2:User) 
OPTIONAL MATCH r5=(t)-[:AFFECTS_SITE]->(cs)<-[:HAS_SITE]-(c:Customer) 
RETURN r1, r2, r3, r4, r5 

注意到将近一分钟,为产生〜7000行的用户运行。我试图重新组织它并没有多大用处。以下是目前的配置文件。

enter image description here

什么或许可以帮忙,有什么建议?

+0

第一条建议:在此查询上使用PROFILE,并在配置文件生成的树中展开所有节点,然后将该配置文件粘贴到您的描述中。这应该是找出性能问题的共同起点。此外,您是否可以确认查询的输出是否正确,或者是否产生任何意想不到的数据或数据结果。此外,我假设User.id有一个唯一的约束......是真的吗? – InverseFalcon

+0

数据看起来是正确的,你是正确的,User.id是一个唯一的约束。 – Greg

+0

我认为下一个有用的东西是要弄清楚是否有任何你真正不需要的数据,如果我们可以收集某些结果而不是每个结果输出一行。例如,您似乎想要返回具有与票证关联的TicketEvents的用户,以及具有受票证影响的站点的客户。您是否需要返回关联的TicketEvents和网站,或者您是否需要了解与这些相关的用户和/或客户?我们是否可以将这些作为用户或客户的集合输出,或者您是否需要每行一行? – InverseFalcon

回答

1

我强烈建议根据需要从OPTIONAL MATCHES收集结果,并使用WITH来分解查询并缩小您感兴趣的列,以便在子查询之间保留行。正如问题评论中所解释的,MATCHES和OPTIONAL MATCHES可以建立结果行,这可以使SEEM查询成为快速昂贵的结果行。

例如,我会添加注释来分析原始查询在线:

MATCH (u:User)-[:CAN_ADMINISTER]->(cs:CustomerSite) 
WHERE u.id="1234" WITH cs 
MATCH r1=(cs)<-[:AFFECTS_SITE]-(t:Ticket) 
WHERE not(t.status = "COMPLETE") 
// we have 1 row per User at a CustomerSite 
OPTIONAL MATCH r2=(t)-[:HAS_EVENTS]->(te:TicketEvent) 
// now, 1 row per User @ CustomerSite per TicketEvent 
OPTIONAL MATCH r3=(t)-[:CREATED_BY]->(u:User) 
// the above OPTIONAL MATCH had to iterate over each User/CS/TE row instead of just each distinct TICKET 
OPTIONAL MATCH r4=(te)<-[:HAS_EVENTS]-(u2:User) 
// now, 1 row per User @ CustomerSite per User on each Ticket Event 
OPTIONAL MATCH r5=(t)-[:AFFECTS_SITE]->(cs)<-[:HAS_SITE]-(c:Customer) 
// now, 1 row per User @ CustomerSite per User on each Ticket Event per Customer at each Customer Site 
RETURN r1, r2, r3, r4, r5 

虽然它改变了返回的数据格式,一路上做收集,并订购您可选MATCHES更好,要提高查询速度。这里是你可以做到这一点的一种方法:

MATCH (u:User)-[:CAN_ADMINISTER]->(cs:CustomerSite) 
WHERE u.id="1234" WITH cs 
MATCH (cs)<-[:AFFECTS_SITE]-(t:Ticket) 
WHERE not(t.status = "COMPLETE") 
// should be 1 creator per ticket, so best to do this first 
OPTIONAL MATCH (t)-[:CREATED_BY]->(creator:User) 
OPTIONAL MATCH (cs)<-[:HAS_SITE]-(affectedCustomer:Customer) 
// collection of affected customers for each ticket (and their creator) affecting a customer site 
WITH cs, t, creator, COLLECT(affectedCustomer) as affectedCustomers 
OPTIONAL MATCH (t)-[:HAS_EVENTS]->(te:TicketEvent)<-[:HAS_EVENTS]-(userOnEvent:User) 
WITH cs, t, creator, affectedCustomers, te, COLLECT(userOnEvent) as usersOnEvent 
RETURN cs, t, creator, affectedCustomers, COLLECT({ticketEvent:te, usersOnEvent:usersOnEvent}) as ticketEventsAndUsers 

每一行都将在客户站点,车票的创造者,受影响的用户在网站的集合,门票事件的门票集合的票对应并为事件,该事件的用户。

试试看看性能如何比较。如果它看起来更好,你将不得不改变你如何解析返回的数据,但对于循环或两个无法处理的循环来说,这无关紧要。

+0

这是有帮助的 - 感谢您的好解释 – Greg