我有一个
Vacancy
节点,它与 Country
相关(Country
也有标签 Requirable
):
(v:Vacancy)-[:WORK_PERMIT_IN]-(:Country)
此外,
Vacancy
有一个非规范化属性workCountryIds
,其中包含国家/地区的所有ID。
您能否建议就大型数据集的性能而言,哪种方法最适合在 Neo4j 中用于 WHERE 谓词:
MATCH ( v:Vacancy )
WHERE ( coalesce(size(v.workCountryIds), 0) <= 0 OR exists { MATCH (v)-[:WORK_PERMIT_IN]-(req3:Requirable) WHERE req3.id IN [11, 12, 13]} )
RETURN v
或
MATCH ( v:Vacancy )
WHERE ( NOT exists { MATCH (v)-[:WORK_PERMIT_IN]-(:Country)} OR exists { MATCH (v)-[:WORK_PERMIT_IN]-(req3:Requirable) WHERE req3.id IN [11, 12, 13]} )
RETURN v
在第一种情况下,我使用:
coalesce(size(v.workCountryIds), 0) <= 0
第二个:
NOT exists { MATCH (v)-[:WORK_PERMIT_IN]-(:Country)}
这两种方法在性能方面使用哪种更好?
您的第二种情况必须遵循每个
WORK_PERMIT_IN
的 Vacancy
关系,以检查另一端是否没有 Country
节点(在最坏的情况下,它必须检查每个这样的节点)。但是你的第一个案例只需要查看每个 Vacancy
节点的一个属性(完全忽略关系),所以它会更快。 [注意:如果 WORK_PERMIT_IN
关系 always 连接 Vacancy
和 Country
节点,那么通过将 (:Country)
更改为 ()
,第二种情况会更快,并且您还应该使关系模式具有方向性。但即使进行了这些调整,第二种情况也会变慢。]
但是,实际上还存在另一个与性能有关的问题,并且在您的两种情况下都存在。我将用你的第一个案例来说明,因为那已经更快了。这是您的第一个案例(为了可读性而重新格式化):
MATCH (v:Vacancy)
WHERE
// (a)
COALESCE(SIZE(v.workCountryIds), 0) <= 0 OR
// (b)
EXISTS {
MATCH (v)-[:WORK_PERMIT_IN]-(req3:Requirable)
WHERE req3.id IN [11, 12, 13]
}
RETURN v
您返回的职位空缺是:(a) 未连接到任何
Country
,或 (b) 连接到一些所需的 Requirable
节点。 (b) 的实现效率很低,因为只要 (a) 不适用,它就会执行 MATCH (v)-[:WORK_PERMIT_IN]-(req3:Requirable)
,这可能是大多数 v
的情况。并且,假设有很多 Requirable
id,那么在几乎每个 MATCH
上执行该 v
而不是仅连接到 3 个所需 Requirable
节点的空位是非常浪费的。
这个查询应该更高效:
// (a)
MATCH (v1:Vacancy)
WHERE COALESCE(SIZE(v1.workCountryIds), 0) = 0
WITH COLLECT(v1) AS v1List
// (b)
MATCH (v2)-[:WORK_PERMIT_IN]->(req:Requirable)
WHERE req.id IN [11, 12, 13] AND NOT v2 IN v1List
WITH v1List, COLLECT(v2) AS v2Listrequired ids
// Return combined (a) and (b) results
RETURN v1List + v2List AS v