Cypher - 查询优化

时间:2017-07-24 07:12:55

标签: neo4j cypher spring-data-neo4j

我的问题是为什么WHERE运算符的工作速度不如预期的那么快? 考虑我有7个带有标签Consumer的节点。以下是一些示例数据...

MERGE (c:Consumer {mobileNumber: "000000000000"})
MERGE (:Consumer {mobileNumber: "111111111111"})
MERGE (:Consumer {mobileNumber: "222222222222"})
MERGE (:Consumer {mobileNumber: "333333333333"})
MERGE (:Consumer {mobileNumber: "444444444444"})
MERGE (:Consumer {mobileNumber: "555555555555"})
MERGE (:Consumer {mobileNumber: "666666666666"})
WITH c
MATCH (c1:Consumer) WHERE c1.mobileNumber <> "000000000000"
MERGE (c)-[:HAS_CONTACT]->(c1)

HAS_CONTACT与所有其他6个节点之间存在:Consumer(mobileNumber:{"000000000000"})关系。此外,unique index字段还有mobileNumber个约束。现在,当我尝试执行以下查询时:

    PROFILE MATCH (n:Consumer{mobileNumber : "000000000000"}),
    (m:Consumer{mobileNumber : "111111111111"}) 
    WITH n,m 
    MATCH path = SHORTESTPATH((n)-[contacts:HAS_CONTACT]-(m)) 
    RETURN contacts;

所以它的工作正常如预期(基于唯一索引的搜索节点)。以下是其结果: Without Where clause

现在让我们使用WHERE子句更改上面的查询:

PROFILE MATCH (n:Consumer{mobileNumber : "000000000000"}),
(m:Consumer) WHERE m.mobileNumber 
IN (["111111111111"]) 
WITH n,m 
MATCH path = SHORTESTPATH((n)-[contacts:HAS_CONTACT]-(m)) 
RETURN contacts;

查询结果: With WHERE clause

现在虽然上面的查询工作正常,并且给出与旧的查询相同的结果。但是对于我使用WHERE子句的endNode,它并没有使用任何索引。它首先搜索所有现有节点,然后使用WHERE子句过滤结果,如果有数十万个具有相同标签的节点,这可能过于昂贵。

所以我的问题是:

  1. 当我使用WHERE子句时,它为什么不使用索引?
  2. 使用较少数量的db命中引用多个节点的最佳方法是什么?
  3. 我可以在期待索引搜索时使用IN运算符吗?

3 个答案:

答案 0 :(得分:3)

正如@DaveBennett所说,版本3.2.2中似乎不存在这个问题。

如果您使用的是先前版本,请尝试向规划人员提供应使用索引编制的hints

PROFILE MATCH
  (n:Consumer{mobileNumber : "000000000000"}),
  (m:Consumer)
USING INDEX n:Consumer(mobileNumber)
USING INDEX m:Consumer(mobileNumber)
WHERE m.mobileNumber  IN (["111111111111"])
MATCH path = SHORTESTPATH((n)-[contacts:HAS_CONTACT]-(m))
RETURN contacts;

这可能也有效,因为一些规划者似乎会自动尝试(仅)使用第一个MATCH术语的索引:

PROFILE MATCH
  (n:Consumer{mobileNumber : "000000000000"}),
  (m:Consumer)
USING INDEX m:Consumer(mobileNumber)
WHERE m.mobileNumber  IN (["111111111111"])
MATCH path = SHORTESTPATH((n)-[contacts:HAS_CONTACT]-(m))
RETURN contacts;

答案 1 :(得分:2)

你在运行什么版本?我正在使用3.2.2社区版,您的第二个查询使用您的小测试数据集生成了您在本地实例中搜索的结果。

那就是说,查询规划器是否在你的实例中改变了它的方法?

keyup.enter

答案 2 :(得分:0)

在此示例中,索引实际上与WHERE子句一起使用:

PROFILE MATCH (n:Consumer{mobileNumber : "000000000000"}),
(m:Consumer) WHERE m.mobileNumber = "111111111111"
WITH n,m 
MATCH path = shortestPath((n)-[contacts:HAS_CONTACT]-(m)) 
RETURN contacts

使用索引作为您的第一个查询。如果要引用多个节点,可以使用逻辑谓词,如:

PROFILE MATCH (n:Consumer{mobileNumber : "000000000000"}),
(m:Consumer) WHERE m.mobileNumber = "111111111111" OR m.mobileNumber = "222222222222"
WITH n,m 
MATCH path = shortestPath((n)-[contacts:HAS_CONTACT]-(m)) 
RETURN contacts

AND代替OR

我认为当使用IN子句查看数组时,当前版本的Neo4j不支持使用索引。