CRUDRepository的保存方法非常缓慢



我想在neo4j数据库中存储一些数据。我使用spring-data-neo4j。

我的代码如下:

    for (int i = 0; i < newRisks.size(); i++) {
        myRepository.save(newRisks.get(i));
        System.out.println("saved " + newRisks.get(i).name);
    }

我的newRisks数组包含大约60000个对象和60000条边。每个节点和边都有一个属性。这个循环的持续时间大约是15-20分钟,这正常吗?我使用JavaVisualVM来搜索一些瓶颈,但我的平均CPU使用率是10-25%(4核),堆还不到一半。

有什么方案可以加强这次行动吗?


EDIT:额外的是,在myRepository.save(newRisks.get(i));的第一次调用中,jvm在第一次输出混合之前几分钟就被唤醒了

第二版:

类别风险:

@NodeEntity
public class Risk {
    //...
    @Indexed
    public String name;
    @RelatedTo(type = "CHILD", direction = Direction.OUTGOING)
    Set<Risk> risk = new HashSet<Risk>();
    public void addChild(Risk child) {
        risk.add(child);
    }
    //...
}

制造风险:

@Autowired
private Repository myRepository;
@Transactional
public Collection<Risk> makeSomeRisks() {
    ArrayList<Risk> newRisks = new ArrayList<Risk>();
    newRisks.add(new Risk("Root"));
    for (int i = 0; i < 60000; i++) {
        Risk risk = new Risk("risk " + (i + 1));
        newRisks.get(0).addChild(risk);
        newRisks.add(risk);
    }
    for (int i = 0; i < newRisks.size(); i++) {
        myRepository.save(newRisks.get(i));
    }
    return newRisks;
}

这里的问题是,您正在使用API进行批量插入,而这并不是为了这个目的。

你创建了一个Risk和60k个子项,你首先保存根,它同时也保持了60k子项(并创建了关系)。这就是为什么第一次扑救需要这么长时间。然后你又救了孩子们。

有一些解决方案可以通过SDN.来加快速度

  1. 不要对大量插入使用收集方法,保留参与者并使用template.createRelationshipBetween(root,child,"child",false);

  2. 先持久化子对象,然后将所有持久化的子对象添加到根对象并持久化

  3. 正如您所做的,使用Neo4j-Core API,但调用template.postEntityCreation(node,Risk.class),这样您就可以通过SDN访问实体。然后,您还必须自己对实体进行索引(db.index.forNodes("Risk").add(node),"name",name);)(或者使用neo4j核心api自动索引,但这与SDN不兼容)。

  4. 无论核心api或SDN如何,您都应该使用10-20k个节点/rel左右的tx大小来获得最佳性能

我想我找到了一个解决方案:

我使用原生neo4jjava API尝试了相同的插入:

GraphDatabaseService graphDb;
Node firstNode;
Node secondNode;
Relationship relationship;
graphDb = new EmbeddedGraphDatabase(DB_PATH);
Transaction tx = graphDb.beginTx();
try {
    firstNode = graphDb.createNode();
    firstNode.setProperty( "name", "Root" );
    for (int i = 0; i < 60000; i++) {
        secondNode = graphDb.createNode();
        secondNode.setProperty( "name", "risk " + (i+1));
        relationship = firstNode.createRelationshipTo( secondNode, RelTypes.CHILD );
    }
    tx.success();
}
finally {
    tx.finish();
    graphDb.shutdown();
}

结果:经过一些sconds,数据库充满了风险。

也许这些反射减缓了spring-data-neo4j的日常工作@Michael Hunger在他的书《GoodRelationships》中说过这样的话,谢谢你的提示。

插入数据库(Java之外)是否有相同的延迟,或者这只是通过spring数据造成的问题?

我遇到了与OP相同的问题。在我的情况下,真正有用的是将Neo4j的使用从远程服务器模式更改为嵌入式。嵌入式SDN使用的好例子可以在这里找到。

最新更新