[英]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.