[英]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将结果汇总到更少的行,以使其余密码更便宜。在这种情况下,该方法不适用)
您应该始终在查询中尽早放置WHERE
子句。 这样可以过滤掉其余查询将不需要处理的数据,从而避免了不必要的工作。
您应该避免编写仅传递所有定义的变量(语法上不需要)的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.