我的问题是为什么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;
所以它的工作正常如预期(基于唯一索引的搜索节点)。以下是其结果:
现在让我们使用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;
现在虽然上面的查询工作正常,并且给出与旧的查询相同的结果。但是对于我使用WHERE
子句的endNode,它并没有使用任何索引。它首先搜索所有现有节点,然后使用WHERE
子句过滤结果,如果有数十万个具有相同标签的节点,这可能过于昂贵。
所以我的问题是:
WHERE
子句时,它为什么不使用索引? IN
运算符吗?答案 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不支持使用索引。