【问题标题】:Neo4j merge performance VS create/setNeo4j 合并性能 VS 创建/设置
【发布时间】:2015-05-22 18:26:00
【问题描述】:

我在 Neo4j 中存储了一棵树,在树中,每个节点都包含一个标识符和一个计数器。我希望能够为一堆节点快速增加该计数器。

所以我使用了 MERGE(使用 ON CREATE SET 和 ON MATCH SET),但是性能很差。似乎如果我用两个事务来做,一个知道每个节点是否存在,另一个来创建或更新它,它会更快。

您知道为什么 MERGE 比 MATCH 和 CREATE 结合起来要慢吗?我怎样才能提高它的性能?

这是一个您可以复制的相关示例:

import datetime
from py2neo import Graph

def bench(query, count, reset=True):
    graph = Graph()

    if reset:
        graph.cypher.run("MATCH (n) OPTIONAL MATCH (n)-[r]-() DELETE n,r")
        graph.cypher.run("CREATE CONSTRAINT ON (node:Node) ASSERT node.number IS UNIQUE")
        graph.cypher.run("CREATE (r:Root)")

    start = datetime.datetime.now()
    tx = graph.cypher.begin()
    for i in range(count):
        tx.append(query, {'i': i})
    tx.commit()

    print('---')
    print('query : %s' % query)
    print("%i create. %s/second." % (count, count // (datetime.datetime.now() - start).total_seconds()))

if __name__ == '__main__':
    bench("MATCH (:Root)-[:Child]->(n:Node {number: {i}}) RETURN n.count", 1000)
    bench("CREATE (:Root)-[:Child]->(:Node {number: {i}, count: 1})", 1000)
    bench("MATCH (root:Root) CREATE (root)-[:Child]->(:Node {number: {i}, count: 1})", 1000)
    bench("MATCH (root:Root) MERGE (root)-[:Child]->(n:Node {number: {i}}) ON CREATE SET n.count = 1 ON MATCH SET n.count = n.count + 1", 1000)
    bench("MATCH (root:Root)-[:Child]->(n:Node {number: {i}}) SET n.count = n.count + 1", 1000)
    bench("MATCH (root:Root) CREATE UNIQUE (root)-[:Child]->(n:Node {number: {i}}) SET n.count = coalesce(n.count, 0) + 1", 1000)

以及该代码的输出:

---
query : MATCH (:Root)-[:Child]->(n:Node {number: {i}}) RETURN n.count
1000 create. 1151.0/second.
---
query : CREATE (:Root)-[:Child]->(:Node {number: {i}, count: 1})
1000 create. 760.0/second.
---
query : MATCH (root:Root) CREATE (root)-[:Child]->(:Node {number: {i}, count: 1})
1000 create. 1092.0/second.
---
query : MATCH (root:Root) MERGE (root)-[:Child]->(n:Node {number: {i}}) ON CREATE SET n.count = 1 ON MATCH SET n.count = n.count + 1
1000 create. 218.0/second.
---
query : MATCH (root:Root)-[:Child]->(n:Node {number: {i}}) SET n.count = n.count + 1
1000 create. 3005.0/second.
---
query : MATCH (root:Root) CREATE UNIQUE (root)-[:Child]->(n:Node {number: {i}}) SET n.count = coalesce(n.count, 0) + 1
1000 create. 283.0/second.

感谢您的帮助:)

【问题讨论】:

    标签: performance neo4j


    【解决方案1】:

    MERGE 和 CREATE UNIQUE 都必须先检查关系和端节点,然后再创建。

    如果您先创建子节点然后在关系上合并,则使用 MERGE 会更快。

    只有一个绑定节点的合并变体将总是创建一个新的子节点!!

    试试这个:

    MATCH (root:Root) 
    MERGE (n:Node {number: {i}}) 
      ON CREATE SET n.count = 1 ON MATCH SET n.count = n.count + 1
    MERGE (root)-[:Child]->(n)
    

    或者这个

    MATCH (root:Root) 
    MERGE (n:Node {number: {i}}) 
      ON CREATE SET n.count = 1 ON MATCH SET n.count = n.count + 1
    CREATE UNIQUE (root)-[:Child]->(n)
    

    【讨论】:

      【解决方案2】:

      您可以在 Web 界面中使用 PROFILE 或通过 neo4j-shell 仔细查看您的查询:http://neo4j.com/docs/stable/how-do-i-profile-a-query.html

      这可能有助于了解MERGE 为何如此缓慢。

      PROFILE MATCH (root:Root) MERGE (root)-[:Child]->(n:Node {number: 1})
      ON CREATE SET n.count = 1 ON MATCH SET n.count = n.count + 1
      

      看看MERGE 是否以及为什么带有ON MATCHON MATCHMATCH ... SETonly 会很有趣。也许 cypher 对两个查询使用不同的索引,PROFILE 也告诉你这一点。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-05-11
        • 2019-10-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多