簡體   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