neo4j 的索引index 在where语句里不生效
发布于 3 年前 作者 mzhenma 468 次浏览 来自 问答

Server 版本 4.3.1

  1. 本地创建index:CREATE INDEX Supply_id_index IF NOT EXISTS FOR (l:SupplyPlan) ON (l.id);

  2. 执行explain

explain MATCH (shipment:`Shipment` {tenantId: '0804', type: 'Shipment'}) 
WHERE EXISTS {
  MATCH (shipment:`Shipment`)-[:`Shipment_SupplyPlan_supplyPlan` {fieldName: 'supplyPlan'}]->(supplyPlan:`SupplyPlan`) 
  WHERE supplyPlan.id = '0804-01'
}
RETURN shipment;

发现有 NodeIndexSeek@neo4,应该是命中了index

  1. 插入Shipment和Supply的点和边
CREATE (shipment:Shipment {type: 'Shipment', tenantId: "0804", id:"0804-shipment-1"});
CREATE (supplyPlan:SupplyPlan {type: 'SupplyPlan', tenantId: "0804", id:"0804-01"});
MATCH (shipment:Shipment),(supplyPlan:SupplyPlan) 
WHERE shipment.id = "0804-shipment-1" AND supplyPlan.id = "0804-01" 
CREATE (shipment)-[r:`Shipment_SupplyPlan_supplyPlan` {fieldName: 'supplyPlan'}]->(supplyPlan) 
RETURN type(r), r.fieldName;
  1. 同样再去执行上面的explain,发现是NodeByLabelScan@neo4j,没有命中index

  2. 在where中不用exists,换一个query方式,

explain MATCH (shipment:`Shipment` {tenantId: '0804', type: 'Shipment'})-[:`Shipment_SupplyPlan_supplyPlan` {fieldName: 'supplyPlan'}]->(supplyPlan:`SupplyPlan`) 
WHERE supplyPlan.id = '0804-01'
RETURN shipment; 

发现有NodeIndexSeek@neo4,命中了index

问题:为什么在where中用exists时,插了数据之后反而不能命中索引?求告知

1 回复

个人认为类似下面两行这种cypher应该是要避免的 MATCH (shipment:Shipment),(supplyPlan:SupplyPlan) WHERE shipment.id = “0804-shipment-1” AND supplyPlan.id = "0804-01" 应该拆成两个cypher来做才能保证都能使用索引,这种没有任何关系的节点放一起没什么好处,某些情况下坏处比较多。我在一些文档上看到过单个cypher query的planner默认用一个索引,因此我猜想你的执行计划里用上了一个index,如果要multple indexes需要使用hint use index 显式指定执行多索引,不知道现在新版本有变化没。 总之这种cypher写法不是最佳实践,某些情况下比较低效。 应该拆分成分别查询的两个简单cypher比较好。 另外我觉得如果最好用profile来打印执行计划,explain并不真的执行cypher,因此不排除产生的执行计划与实际不符的情况。

回到顶部