繁体   English   中英

当查询具有WHERE和WITH子句时的Neo4j Cypher执行计划

[英]Neo4j Cypher execution plan when query has WHERE and WITH clause

我有一个Neo4j图形数据库,用于存储人员配置关系和节点。 我必须编写一个密码,以找到资源(或员工)的家庭和办公室地址以及他们的empId和名称。 这是必需的,以便“人员配备解决方案”可以根据他们的家庭位置以及附近的办公室来配备人员。

MATCH (employee:Employee) <-[:ADDRESS_TO_EMPLOYEE]- (homeAddress:HomeAddress) 
WHERE employee.id = '70' 
WITH  employee, homeAddress 
MATCH (employee)-[:EMPLOYEE_TO_OFFICEADDRESS]->(officeAddress:OfficeAddress) 
RETURN employee.empId, employee.name,  
homeAddress.street, homeAddress.area, homeAddress.city,  
officeAddress.street, officeAddress.area, officeAddress.city

该密码返回期望的结果。

但是,如果我将WHERE条件移到最后一个位置,就在RETURN子句之前。

MATCH (employee:Employee) <-[:ADDRESS_TO_EMPLOYEE]- (homeAddress:HomeAddress) 
WITH  employee, homeAddress  
MATCH (employee)-[:EMPLOYEE_TO_OFFICEADDRESS]->(officeAddress:OfficeAddress) 
WHERE employee.id = '70' 
RETURN employee.empId, employee.name,  
homeAddress.street, homeAddress.area, homeAddress.city,  
officeAddress.street, officeAddress.area, officeAddress.city 

它再次给了我相同的结果。

那么在这两种情况下,哪个查询查询计划是最优化的呢? 我的意思是数据库命中次数和返回的记录数相同。

现在,如果我删除WITH子句,

MATCH (employee:Employee) <-[:ADDRESS_TO_EMPLOYEE]- 
(homeAddress:HomeAddress),
MATCH (employee)-[:EMPLOYEE_TO_OFFICEADDRESS]->(officeAddress:OfficeAddress) 
WHERE employee.id = '70' 
RETURN employee.empId, employee.name, 
homeAddress.street, homeAddress.area, homeAddress.city, 
officeAddress.street, officeAddress.area, officeAddress.city

然后结果又是一样的,执行计划也一样。

在这种情况下,我真的需要WITH吗?

任何帮助将不胜感激。

首先,您可以使用Profile and Explain来获得查询的性能。 但是,只要您在想要的时间内获得想要的结果,密码就不会太在意,因为行为会根据数据库中运行的密码计划器(版本)而改变。 因此,只要密码通过了单元测试和负载测试,其余的都没关系(假设测试相当准确)。

其次,总的来说,少即是多。 想象一下,您必须阅读自己的密码,然后在纸质打印件上自行查找信息。 不是MATCH (officeAddress:OfficeAddress)<-[:EMPLOYEE_TO_OFFICEADDRESS]-(employee:Employee {id:'70'})<-[:ADDRESS_TO_EMPLOYEE]-(homeAddress:HomeAddress)这么容易分辨出您要查找的内容对于? Cypher计划者越容易阅读您想要的内容,Cypher计划者就越有可能计划最有效的查找策略。 另外,将WHERE子句保持在相关匹配范围附近也有助于计划者。 因此,尝试使密码尽可能简单,同时仍能准确满足您的需求。

在您的Cypher中,唯一重要的部分是WITH。 WITH将在密码中产生逻辑中断,并更改变量的范围。由于您对with并没有做任何事情,因此最好将其删除。 在这种情况下,它可能产生的唯一副作用是诱使Cypher进行比第一次比赛所需的工作更多的工作,以便稍后对其进行过滤。 如果一个雇员的家庭住址要比WITH employee, COLLECT(homeAddress) as homeAdress会将每名雇员的匹配减少到1行,使下一次匹配更便宜,但是由于我确信匹配的双方应该只产生1个结果,计划者先做什么都没关系。 (通常,您可以使用with将结果汇总到更少的行,以使其余密码更便宜。在这种情况下,该方法不适用)

  1. 您应该始终在查询中尽早放置WHERE子句。 这样可以过滤掉其余查询将不需要处理的数据,从而避免了不必要的工作。

  2. 您应该避免编写仅传递所有定义的变量(语法上不需要)的WITH子句,因为它本质上是无操作的。 计划者的处理工作浪费(一点点)时间,并使Cypher代码更难以理解。

这个简单的查询版本应产生相同的查询计划:

MATCH (officeAddress:OfficeAddress)<-[:EMPLOYEE_TO_OFFICEADDRESS]-(employee:Employee)<-[:ADDRESS_TO_EMPLOYEE]-(homeAddress:HomeAddress) 
WHERE employee.id = '70' 
RETURN
  employee.empId, employee.name,  
  homeAddress.street, homeAddress.area, homeAddress.city,  
  officeAddress.street, officeAddress.area, officeAddress.city

以下版本(使用地图投影语法)甚至更简单(具有类似的查询计划)。

MATCH (officeAddress:OfficeAddress)<-[:EMPLOYEE_TO_OFFICEADDRESS]-(employee:Employee)<-[:ADDRESS_TO_EMPLOYEE]-(homeAddress:HomeAddress) 
WHERE employee.id = '70' 
RETURN
  employee{.empId, .name},  
  homeAddress{.street, .area, .city},  
  officeAddress{.street, .area, .city}

但是,上述查询的结果具有不同的结构:

╒═══════════════════════════╤══════════════════════════════════════╤══════════════════════════════════════╕
│"employee"                 │"homeAddress"                         │"officeAddress"                       │
╞═══════════════════════════╪══════════════════════════════════════╪══════════════════════════════════════╡
│{"name":"sam","empId":"70"}│{"area":1,"city":"foo","street":"123"}│{"area":2,"city":"bar","street":"345"}│
└───────────────────────────┴──────────────────────────────────────┴──────────────────────────────────────┘

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM