19

CSV ファイルを処理し、レコード (行) ごとにエンティティを保持する必要があります。今、私はこのようにしています:

while ((line = reader.readNext()) != null) {
    Entity entity = createEntityObject(line);
    entityManager.save(entity);
    i++;
}

save(Entity)メソッドは基本的に単なる呼び出しEntityManager.merge()です。CSV ファイルには約 20,000 のエンティティ (行) があります。これは効果的な方法ですか?かなり遅いようです。を使った方が良いでしょうEntityManager.persist()か?このソリューションには何らかの欠陥がありますか?

EDITこれは長いプロセス(400秒以上)であり、と

の両方のソリューションを試しました。どちらも完了までにかかる時間はほぼ同じです (459 秒と 443 秒)。問題は、このようにエンティティを 1 つずつ保存することが最適かどうかです。私の知る限り、Hibernate (私の JPA プロバイダー) はいくつかのキャッシュ/フラッシュ機能を実装しているので、これについて心配する必要はありません。persistmerge

4

4 に答える 4

13

JPA APIは、これを最適化するためのすべてのオプションを提供するわけではありません。これを実行する速度に応じて、ORM固有のオプションを探す必要があります-あなたの場合は休止状態です。

チェックすること:

  1. 単一のトランザクションを使用していることを確認してください(はい、明らかにこれを確信しています)
  2. JPAプロバイダー(Hibernate)がJDBCバッチAPIを使用していることを確認してください(参照:hibernate.jdbc.batch_size)
  3. 生成されたキーの取得をバイパスできるかどうかを確認します(db / jdbcドライバーによって、これからどれだけのメリットが得られるかによって異なります。参照:hibernate.jdbc.use_getGeneratedKeys)
  4. カスケードロジックをバイパスできるかどうかを確認します(これによるパフォーマンス上のメリットは最小限に抑えられます)

したがって、Ebean ORMでは、これは次のようになります。

    EbeanServer server = Ebean.getServer(null);

    Transaction transaction = server.beginTransaction();
    try {
        // Use JDBC batch API with a batch size of 100
        transaction.setBatchSize(100);
        // Don't bother getting generated keys
        transaction.setBatchGetGeneratedKeys(false);
        // Skip cascading persist 
        transaction.setPersistCascade(false);

        // persist your beans ...
        Iterator<YourEntity> it = null; // obviously should not be null 
        while (it.hasNext()) {
            YourEntity yourEntity = it.next();
            server.save(yourEntity);
        }

        transaction.commit();
    } finally {
        transaction.end();
    }

ああ、生のJDBCを介してこれを行う場合は、ORMオーバーヘッド(オブジェクト作成/ガベージコレクションなど)をスキップするので、そのオプションを無視しません。

そうです、これはあなたの質問に答えませんが、より多くのORM固有のバッチ挿入の微調整を検索するのに役立つかもしれません。

于 2011-04-14T04:20:21.127 に答える
6

これを行う一般的な方法の 1 つは、トランザクションを使用することだと思います。新しいトランザクションを開始してから多数のオブジェクトを永続化すると、トランザクションをコミットするまで実際には DB に挿入されません。コミットするアイテムが多数ある場合、これにより効率が向上します。

EntityManager.getTransactionをチェックしてください

于 2011-04-13T13:21:23.840 に答える
5

高速化するには、少なくとも Hibernate では、一定数の挿入後に flush() と clear() を実行します。私は何百万ものレコードに対してこのアプローチを行ってきましたが、うまくいきます。それでも遅いですが、やらないよりはずっと速いです。基本的な構造は次のようになります。

int i = 0;
for(MyThingy thingy : lotsOfThingies) {

    dao.save(thingy.toModel())

    if(++i % 20 == 0) {
        dao.flushAndClear();
    }

}
于 2011-04-13T13:29:39.233 に答える
4

従来のSQLInsertステートメントを使用してデータベースに直接書き込むことができます。

@See EntityManager.createNativeQuery

于 2011-04-13T12:53:19.670 に答える