Neo4j合并性能与创建/设置性能的比较

3
我有一棵存储在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.

感谢您的帮助 :)
2个回答

2

MERGE和CREATE UNIQUE都需要首先检查关系和终端节点,然后再创建。

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

你的这个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)

1
你可以通过网络界面或者neo4j-shell使用PROFILE更仔细地查看你的查询情况: 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

如果只使用ON MATCH而不是MATCH ... SET,看看MERGE是否会变慢,以及为什么会变慢,这将会很有趣。也许Cypher在两个查询中使用的索引不同,PROFILE也可以告诉你这一点。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接