如何优化此密码查询以获得更快的结果

How to optimize this cypher query to get faster Result

the-file-name.csv 是关于上一个问题 How to make the Cypher request to handle those both cases without duplicating Nodes

第一步我做

CREATE CONSTRAINT ON (r:Region) ASSERT r.region IS UNIQUE;
CREATE CONSTRAINT ON (c:City) ASSERT c.cityName IS UNIQUE;
CREATE CONSTRAINT ON (s:Sector) ASSERT s.sectorName IS UNIQUE;

这里我放了密码查询。

LOAD CSV WITH HEADERS FROM "file:///the-file-name.csv" as line 
FIELDTERMINATOR ','  
with line as line
OPTIONAL MATCH (n:Region) 
WHERE  n.region contains "BLANKEMPTYVIDE" AND n.identifier= line.CODE_TER 
WITH n, line
CALL apoc.do.when(
   n IS NULL,
  'MERGE (r:Region{region: line.TERRITOIRE}) ON CREATE SET r.description=line.TERRITOIRE ON CREATE SET r.identifier=line.CODE_TER ON CREATE SET r.id = toString(id(r)) RETURN r',
  'RETURN n AS r',
  {n: n, line: line}) YIELD value
WITH value.r AS r, line 
SET r.identifier=line.CODE_TER
SET r.description=line.TERRITOIRE
SET r.region=line.TERRITOIRE
WITH r,line
OPTIONAL MATCH (ci:City) where ci.cityName contains "BLANKEMPTYVIDE" AND ci.regionIdentifier= line.CODE_TER
CALL apoc.do.when(
   ci IS NULL,
  'MERGE (c:City {cityName:line.BRICK}) ON CREATE SET c.identifier=line.CODE_BRICK ON CREATE SET c.region=line.TERRITOIRE ON CREATE SET c.regionIdentifier=line.CODE_TER ON CREATE SET c.zip=line.CODE_BRICK ON CREATE SET c.description=line.BRICK ON CREATE SET c.id = toString(id(c)) RETURN c',
  'RETURN ci AS c',
  {ci: ci, line: line}) YIELD value
WITH value.c AS c,line,r
SET c.identifier=line.CODE_BRICK 
SET c.region=line.TERRITOIRE
SET c.regionIdentifier=line.CODE_TER
SET c.zip=line.CODE_BRICK
SET c.description=line.BRICK
SET c.cityName=line.BRICK  
WITH c,r,line
MATCH (c {identifier:line.CODE_BRICK}),(r {identifier:line.CODE_TER})
MERGE (c)-[:IS_A_City_BELONGING_TO]->(r)
WITH c,r,line
OPTIONAL MATCH (sec:Sector) 
WHERE  sec.description contains "BLANKEMPTYVIDE" AND sec.regionIdentifier=line.CODE_TER 
CALL apoc.do.when(
   sec IS NULL,
  'MERGE (s:Sector {sectorName:line.SOUSBRICK}) ON CREATE SET s.identifier=line.CODE_SBRICK ON CREATE SET s.region=line.TERRITOIRE ON CREATE SET s.regionIdentifier=line.CODE_TER ON CREATE SET s.city=line.BRICK ON CREATE SET s.cityIdentifier=line.CODE_BRICK ON CREATE SET s.description=line.SOUSBRICK ON CREATE SET s.zip=line.SOUSBRICK ON CREATE SET s.id = toString(id(s)) RETURN s',
  'RETURN sec AS s',
  {sec: sec, line: line}) YIELD value
WITH value.s AS s,line,c,r
SET s.identifier=line.CODE_SBRICK 
SET s.region=line.TERRITOIRE 
SET s.regionIdentifier=line.CODE_TER 
SET s.city=line.BRICK 
SET s.cityIdentifier=line.CODE_BRICK 
SET s.description=line.SOUSBRICK 
SET s.zip=line.SOUSBRICK 
SET s.sectorName = line.SOUSBRICK   
WITH s,c,r,line
MATCH (s {identifier:line.CODE_SBRICK}),(r{identifier:line.CODE_TER}) 
MERGE (s)-[:IS_A_SECTOR_BELONGING_TO_THAT_REGION]->(r) 
WITH s,c,r,line
MATCH (s {identifier:line.CODE_SBRICK}),(c{identifier:line.CODE_BRICK})
MERGE (s)-[:IS_A_SECTOR_BELONGING_TO_THAT_CITY]->(c)

结果:

设置 28271 个属性,创建 3400 个关系,在 34985 毫秒后完成。

将 csv 加载到 neo4j 数据库用了将近 35 秒。 请问它在性能视图中是否完美?

对于包含 1665 个 csv 行的 csv 文件 每行包含 6 个字段:(地区)的两个第一个字段,第三个和第四个(城市)以及(部门)的第五个和第六个字段。

如何优化这个 neo4j 查询,使其只需要几秒不到 3 秒?

下面我放了profiler结果图

这里我根据 InverseFalcon

的建议进行了更新
LOAD CSV WITH HEADERS FROM "file:///the-file-name.csv" as line 
FIELDTERMINATOR ','  
with line as line
OPTIONAL MATCH (n:Region) 
WHERE  n.region contains "BLANKEMPTYVIDE" AND n.identifier= line.CODE_TER 
WITH n, line
CALL apoc.do.when(
   n IS NULL,
  'MERGE (r:Region{region: line.TERRITOIRE}) ON CREATE SET r.description=line.TERRITOIRE ON CREATE SET r.identifier=line.CODE_TER ON CREATE SET r.id = toString(id(r)) RETURN r',
  'SET n.identifier=line.CODE_TER  SET n.description=line.TERRITOIRE  SET n.region=line.TERRITOIRE RETURN n AS r',
  {n: n, line: line}) YIELD value
WITH value.r AS r, line 

OPTIONAL MATCH (ci:City) where ci.cityName contains "BLANKEMPTYVIDE" AND ci.regionIdentifier= line.CODE_TER
CALL apoc.do.when(
   ci IS NULL,
  'MERGE (c:City {cityName:line.BRICK}) ON CREATE SET c.identifier=line.CODE_BRICK ON CREATE SET c.region=line.TERRITOIRE ON CREATE SET c.regionIdentifier=line.CODE_TER ON CREATE SET c.zip=line.CODE_BRICK ON CREATE SET c.description=line.BRICK ON CREATE SET c.id = toString(id(c)) RETURN c',
  'SET ci.identifier=line.CODE_BRICK SET ci.region=line.TERRITOIRE SET ci.regionIdentifier=line.CODE_TER SET ci.zip=line.CODE_BRICK SET ci.description=line.BRICK SET ci.cityName=line.BRICK  RETURN ci AS c',
  {ci: ci, line: line}) YIELD value
WITH value.c AS c,line,r
MERGE (c)-[:IS_A_City_BELONGING_TO]->(r)
WITH c,r,line
OPTIONAL MATCH (sec:Sector) 
WHERE  sec.description contains "BLANKEMPTYVIDE" AND sec.regionIdentifier=line.CODE_TER 
CALL apoc.do.when(
   sec IS NULL,
  'MERGE (s:Sector {sectorName:line.SOUSBRICK}) ON CREATE SET s.identifier=line.CODE_SBRICK ON CREATE SET s.region=line.TERRITOIRE ON CREATE SET s.regionIdentifier=line.CODE_TER ON CREATE SET s.city=line.BRICK ON CREATE SET s.cityIdentifier=line.CODE_BRICK ON CREATE SET s.description=line.SOUSBRICK ON CREATE SET s.zip=line.SOUSBRICK ON CREATE SET s.id = toString(id(s)) RETURN s',
  'SET sec.identifier=line.CODE_SBRICK SET sec.region=line.TERRITOIRE SET sec.regionIdentifier=line.CODE_TER SET sec.city=line.BRICK SET sec.cityIdentifier=line.CODE_BRICK SET sec.description=line.SOUSBRICK SET sec.zip=line.SOUSBRICK SET sec.sectorName = line.SOUSBRICK   RETURN sec AS s',
  {sec: sec, line: line}) YIELD value
WITH value.s AS s,line,c,r
MERGE (s)-[:IS_A_SECTOR_BELONGING_TO_THAT_REGION]->(r) 
WITH s,c,r,line
MERGE (s)-[:IS_A_SECTOR_BELONGING_TO_THAT_CITY]->(c)

已添加扇区描述索引 约束变为

CREATE CONSTRAINT ON (r:Region) ASSERT r.region IS UNIQUE;
CREATE CONSTRAINT ON (c:City) ASSERT c.cityName IS UNIQUE;
CREATE CONSTRAINT ON (s:Sector) ASSERT s.sectorName IS UNIQUE;
CREATE CONSTRAINT ON (s:Sector) ASSERT s.description IS UNIQUE;

来自分析器的计划

Cypher 版本:CYPHER 3.4,规划器:COST,运行时:INTERPRETED。 14321 毫秒内总计 175350 次数据库命中 ****

直接不使用 Profiler 创建了 3403 个关系,在 12702 毫秒后完成。

从 36 秒到 12 秒的良好增强,但仍需要优化。

具有最大 DB 命中的操作引用了一个 NodeByLabelScan 后跟一个过滤器,仅产生 1663 行或来自标签的大约 130 万个节点的结果。如果可能的话,这似乎是一个添加索引的机会。

您还没有扩展查询计划中的节点,因此我们看不到关于这些数据库命中与查询的哪一部分相关联的任何信息,但如果我猜它会来自这里:

OPTIONAL MATCH (sec:Sector) 
WHERE  sec.description contains "BLANKEMPTYVIDE" AND sec.regionIdentifier=line.CODE_TER 

我没有看到您在 :Sector(description) 或 :Sector(regionIdentifier) 上创建约束或索引的任何证据,所以这可能是规划器被迫使用 NodeByLabelScan 的地方,就像您一样可见很贵。您将需要其中之一的索引或唯一约束(取决于这些属性中的任何一个是否对 :Sector 是唯一的)。

另外,您在整个查询过程中的几个地方做了一件奇怪的事情,看起来像这样:

MATCH (s {identifier:line.CODE_SBRICK}),(r{identifier:line.CODE_TER}) 

您在 MATCH 中使用的变量已经绑定,因此我建议您对这些变量使用 WHERE 子句,以明确这是一个过滤步骤:

WITH s,c,r,line
WHERE s.identifier = line.CODE_SBRICK AND r.identifier = line.CODE_TER

就是说,在所有这些情况下,您已经明确地将这些属性设置为有问题的行属性,因此无论如何都不需要执行这种过滤,这是不必要的。我建议删除那些匹配项并合并关系。