我有一个neo4j数据库,其中包含带有标签User的节点。在User.user_id属性上建立索引。
执行以下查询确实使用索引:
MATCH (u:User)
WHERE u.user_id = 1234
RETURN u
但是,按如下方式修改查询时,跨越所有记录以检索所需记录的索引将被完全忽略:
MATCH (u:User)
WHERE 1234 is null OR u.user_id = 1234
RETURN u
这种查询的用例是使用多个可选参数进行过滤,例如:
MATCH (u:User)
WHERE ({user_id} is null OR u.user_id = {user_id})
AND ({status} is null or u.status = {status})
AND ({name} is null or u.name = {})
RETURN u
我们如何解释neo4j中的这种行为,而没有变通办法,有哪些可能的修复方法?
查询计划的构建独立于参数求值(请记住查询计划已缓存和重用,因此它不是基于每个查询的,因此在查询计划期间,如下所示:
MATCH (u:User)
WHERE ({user_id} is null OR u.user_id = {user_id})
...
在实际执行索引查找或标签扫描之前没有办法知道,因此默认为标签扫描操作。
作为一种解决方法,您可以使用APOC conditional procedures来执行条件Cypher:
CALL apoc.case([$user_id is not null, "MATCH (u:User {user_id : $user_id} RETURN u", $name is not null, "MATCH (u:User {name:$name}) RETURN u", $status is not null, "MATCH (u:User {status:$status}) RETURN u"], "MATCH (u:User) RETURN u", {user_id:$user_id, name:$name, status:$status}) YIELD value
WITH value.u as u
WHERE ($status is null or u.status = $status)
AND ($name is null or u.name = $name)
...
[如果确实触发了第一个条件以允许对user_id索引进行查找,或者如果触发了第二个条件而允许进行了名称索引查找,则您确实需要保留状态和名称检查,您仍然希望对其余条件进行过滤。
或者,您可以在使用驱动程序的代码中处理此问题,根据您拥有的参数组装或选择要运行的查询。这将使复杂性降低,效率更高。