16

私はアプリケーションの遅延に敏感な部分に取り組んでいます。基本的に、ネットワークイベントを受信して​​データを変換し、すべてのデータをDBに挿入します。プロファイリングした後、基本的にすべての時間がデータの保存に費やされていることがわかりました。ここにコードがあります

private void insertAllData(Collection<Data> dataItems)
{
    long start_time = System.currentTimeMillis();
    long save_time = 0;
    long commit_time = 0;
    Transaction tx = null;
    try
    {
        Session s = HibernateSessionFactory.getSession();
        s.setCacheMode(CacheMode.IGNORE);
        s.setFlushMode(FlushMode.NEVER);
        tx = s.beginTransaction();
        for(Data data : dataItems)
        {
            s.saveOrUpdate(data);
        }
        save_time = System.currentTimeMillis();
        tx.commit();
        s.flush();
        s.clear();
    }
    catch(HibernateException ex)
    {
        if(tx != null)
            tx.rollback();
    }
    commit_time = System.currentTimeMillis();
    System.out.println("Save: " + (save_time - start_time));
    System.out.println("Commit: " + (commit_time - save_time));
    System.out.println();
}

コレクションのサイズは常に 20 未満です。次のタイミング データが表示されます。

Save: 27
Commit: 9

Save: 27
Commit: 9

Save: 26
Commit: 9

Save: 36
Commit: 9

Save: 44
Commit: 0

これは私を混乱させます。は迅速であるsaveべきであり、すべての時間を に費やさなければならないと考えていcommitます。しかし、明らかに私は間違っています。また、トランザクションを削除しようとしましたが(実際には必要ありません)、さらに悪い時間を見ました... hibernate.jdbc.batch_size = 20を設定しました...

1 秒あたり 500 件ものメッセージを取得できると予想されるため、1 つのメッセージ処理を 20 ミリ秒未満にする必要があります。

この操作はできるだけ高速にする必要があります。理想的には、データベースへのラウンドトリップは 1 回だけです。これどうやってするの?

4

3 に答える 3

17

主キーの生成をサーバー側の自動インクリメントから遠ざけます。往復を避けるために、Java コードは PK の生成を担当する必要があります。

適切な一括挿入パフォーマンスを得るには、saveOrUpdate を呼び出すたびにデータベースにアクセスする必要のないメソッドが必要です。UUID を主キーとして使用するか、HiLo を実装すると、これを実現するのに役立ちます。それ以外の場合、実際に一括挿入は行われません。

他の外部システムとのパフォーマンスと相互運用性の両方を得るには、プールされたオプティマイザーまたはプールされたローのオプティマイザーが最適です。

于 2010-06-12T03:21:57.117 に答える
3

正直なところ、あなたのテストとあなたが示している「対策」から何が合理的に結論付けられるかわかりません(ウォームアップからのオーバーヘッドが多く、コレクションは非常に小さく、サンプルは非常に小さいと思われます)。

とにかく、現在のコードはスケーリングされず、より大きなコレクションを渡すとセッションが爆発する可能性が非常に高いと言えます。定期的にセッションをフラッシュしてクリアする必要があります (バッチ サイズが 20 の場合は 20 レコードごと)。

実際には、第 13 章バッチ処理全体を読むことをお勧めします。

于 2010-06-12T02:13:26.817 に答える
0

いくつかの基本的なもの:

  • トリガー、またはインデックスのない外部キー制約がありますか?
  • バッチドライバーはありますか?
  • ドライバーはバッチ モードですか (Pascal のリファレンスの hibernate.jdbc.batch_size を参照)。
  • テーブルにインデックスはありますか (インデックスが多数ある場合、挿入が遅くなることがあります)。

バッチ処理は JDBC 2.0 の一部であり、「バッチ」で複数のステートメントを実行できます。アイデアは、往復の待ち時間を短縮することです (トランザクションごとに複数のバッチを実行できます)。

Statement stmt = dbCon.createStatement("insert into DataTable values (?,?,?)");
stmt.setInt(1, x1); stmt.setInt(2, x2), stmt.setString(3, "some value");
stmt.addBatch();
...
stmt.setInt(1, x2); stmt.setInt(2, x3), stmt.setString(3, "some other value");
stmt.addBatch();

stmt.executeBatch();
dbCon.commit();

おそらくこれをベンチマーク テストとして使用できます。また、hibernate が生成する SQL を調べて、生成された ID を取得するために挿入ごとにクエリを実行しているかどうかを確認します。

于 2010-06-12T02:52:47.263 に答える