performance - 如何提高neo4j基础数据库的性能

标签 performance database-design graph neo4j

我们使用以下查询创建了 neo4j 数据库。我们的 csv 文件包含 50k 行。

// Query1
CREATE CONSTRAINT ON (p:PR) ASSERT p.prId IS UNIQUE;

USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM
'file:///2015_PRData.csv' AS line WITH line,
SPLIT(SPLIT(line.`Open Date`, ' ')[0], '/') AS opnDateList,
SPLIT(SPLIT(line.`Closed Date`, ' ')[0], '/') AS clsDateList
MERGE (prNode:PR{prId:TOINT(line.prId)})
MERGE (app:Application{appName:line.Application})
MERGE (func:Function{funName:line.Function})
MERGE (subfunc:SubFunction{subFunName:line.Subfunction})
MERGE (cat:Category{catName:line.Category})
MERGE (rel:Release{relName:line.Release})
MERGE (custNode:Customer{customerName:line.`Server Name`})
MERGE (prOpenDate:PROpenDate{openDate:SPLIT(line.`Open Date`, ' ')[0]})
SET prOpenDate.day = TOINT(opnDateList[1]),prOpenDate.month = TOINT(opnDateList[0]),prOpenDate.year = opnDateList[2]
MERGE (prClosedDate:PRClosedDate{closedDate:SPLIT(line.`Closed Date`, ' ')[0]})
SET prClosedDate.day = TOINT(clsDateList[1]),prClosedDate.month = TOINT(clsDateList[0]),prClosedDate.year = clsDateList[2]
MERGE (app)-[:PART_OF_APPLN]->(func)
MERGE (func)-[:PART_OF_FUNCTION]->(subfunc)
MERGE (subfunc)-[:PART_OF_SUBFUNCTION]->(cat)
MERGE (prNode)-[:CATEGORY]->(cat)
MERGE (prNode)-[:REPORTED_BY]->(custNode)
MERGE (prNode)-[:OPEN_ON]->(prOpenDate)
MERGE (prNode)-[:CLOSED_ON]->(prClosedDate)
MERGE (prNode)-[:REPORTED_IN]->(rel)

Query 2:
//change year for open date nodes
MERGE (q:PROpenDate) SET q.year=SPLIT(q.year,' ')[0] return q;

Query 3:
//change year for closed date nodes
MERGE (q:PRClosedDate) SET q.year=SPLIT(q.year,' ')[0] return q;

Query 4:
USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM
'file:///2015_PR_WithCP.csv' AS line WITH line
MERGE (cpNode:CP{cpId:line.cpId})
MERGE (prnode:PR{prId:TOINT(SPLIT(line.prRefId, 'PR')[1])})
CREATE (prnode)-[:FIXED_BY]->(cpNode)

Query 5:
USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM
'file:///2015_CPWithFilename.csv' AS line WITH line
MERGE (cpNode:CP{cpId:line.cpId})
MERGE (cpFile:FILE{fileName:line.fileName})
CREATE (cpNode)-[:CONTAINS]->(cpFile)

Query 6:   
USING PERIODIC COMMIT 100
LOAD CSV WITH HEADERS FROM
'file:///2015_CPcomments.csv' AS line
MERGE (cpNode:CP{cpId:line.cpId})
MERGE (fileNode:FILE{fileName:line.fileName})
MERGE (owner:DougUser{userId:line.cpOwner})
MERGE (reviewer:DougUser{userId:line.cpReviewer})
MERGE (cpNode)-[:SUBMITTED_BY]->(owner)
WITH line WHERE line.reviewComment IS NOT NULL
MERGE (comment:ReviewComment{commentText:line.reviewComment,contextCP:line.cpId})
MERGE (comment)-[:GIVEN_BY]->(reviewer)
MERGE (comment)-[:COMMENT_FOR]->(fileNode)

在neo4j中上传数据需要更多的时间。首次查询超过 7 小时。

从服务器获取数据也需要更多时间。

MATCH (pr:PR)-[:FIXED_BY]-(cp) 
MATCH (cp)-[:CONTAINS]-(file)  
MATCH (pr)-[:CLOSED_ON]-(cls) 
MATCH (pr)-[:REPORTED_BY]-(custs) 
MATCH (pr)-[:CATEGORY]-(cats) 
WHERE  file.fileName STARTS WITH 'xyz'  AND NOT(cls.closedDate = '' )AND 
apoc.date.parse(cls.closedDate,'s', 'MM/dd/yyyy') >= apoc.date.parse('01/01/2014','s', 'MM/dd/yyyy') AND apoc.date.parse(cls.closedDate,'s', 'MM/dd/yyyy') <= apoc.date.parse('06/13/2017','s', 'MM/dd/yyyy') 
RETURN collect(DISTINCT custs.customerName) AS customers, collect(DISTINCT cats.catName) AS categories

以上查询需要 5 分钟以上的时间来获取数据。请帮我解决这个问题。性能真的很差。

最佳答案

您的主要问题可能是在执行每个 MERGE 时缺少索引/约束。 MERGE 就像 MATCH 或 CREATE,如果您在 MERGING 的标签/属性上没有索引,则数据库必须执行标签扫描,这意味着它必须检查标签中的每个节点数据库并访问它们的所有属性以查找其中哪些具有您想要的属性,这是昂贵的。当您添加节点时,标签扫描(以及 MERGE)变得越来越慢。请改用索引。

如果您在具有多个属性的节点上使用 MERGE,如果有唯一属性(例如 id 属性),则仅使用该属性进行 MERGE,然后使用 ON CREATE SET 设置剩余的非唯一属性.

您可以在查询之前使用 EXPLAIN 检查效率低下,这将生成查询计划而不执行查询。您要确保看到 NodeUniqueIndexSeek 和 NodeIndexSeek。如果您看到 NodeByLabelScan,那么您很可能需要通过在相关标签/属性上添加索引来优化查询。

您的某些查询在它们应该使用 MATCH 时使用 MERGE(查询 2 和 3,并且可能是后续查询中您知道该节点已存在的某些节点)。如果您尝试在数据库中查找现有节点而不是尝试添加节点,请改用 MATCH。

查询 6 在你的 WITH 子句中有一个缺陷,你还需要在 WITH 中包含 reviewerfileNode,否则这些变量将超出范围并且不会'不会绑定(bind)到您之前在查询中创建的节点。

查询 6 在查询计划中也有一个 Eager(由 ownerreviewer 节点合并引起),这将阻止定期提交并导致查询运行效率低下。要解决此问题,首先导入所有 :DougUser 节点(此处使用单个变量),然后才执行查询 6(但对 ownerreviewer 使用 MATCH ,因为它们应该存在于图中)。

对于查询 7,EXPLAIN 计划显示了一个 NodeByLabelScan,因此它将在所有 :PR 节点上运行以寻找匹配模式。最好将 :FILE 标签添加到 file 节点,这将改变以 NodeIndexSeekByRange 开始的计划,因此您的起始节点将是 :FILE 以 'xyz' 开头的节点(通过快速索引查找),它将从那里找到匹配的模式。

关于performance - 如何提高neo4j基础数据库的性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47570562/

相关文章:

sql-server - 关系数据仓库中的引用完整性。这值得么?有哪些替代方案?

entity-framework - 如何对 : Team <-(1) --- (N)-> Employees, 进行变形建模;更好的模式?

python - "Auto code"基于信号流的编程算法?

algorithm - 在图中查找具有最大最小容量的路径

java - 在这种情况下,表示树的最佳方式是什么?

sql-server - 我可以将查询计划从一台服务器传输到另一台服务器吗?

c# - 结构元组的性能

performance - 使用 SSH 和 SSL 之间的性能差异是什么?

mysql - 每行列子集为空的表的正确设计

定义多个正则表达式以在多次迭代中使用的 Pythonic 和高效方法