5

私は、c# と Fluent NHibernate で構築されたプロジェクトで、さまざまな大規模なデータ変更操作を行っています。DBはsqliteです(パフォーマンスに関心があるため、メモリではなくディスク上にあります)

これらのパフォーマンスをチェックしたかったので、大量のデータをフィードしてプロセスに処理をさせるテストをいくつか作成しました。これらのプロセスのうちの 2 つの結果は、私をかなり混乱させました。

1 つ目は、XML ファイルで提供されたデータを取得し、簡単な処理を行ってインポートする、かなり単純なケースです。XML には約 172,000 行が含まれており、プロセスの実行には合計で約 60 秒かかり、実際の挿入には約 40 秒かかります。

次のプロセスでは、同じデータ セットに対して何らかの処理を行います。したがって、1 つのテーブルに約 172,000 行の DB があります。次に、プロセスはこのデータを処理し、より重い処理を行い、一連の DB 更新 (同じテーブルへの挿入と更新) を生成します。合計すると、約 50,000 行が挿入され、80,000 行が更新されます。この場合、処理には約 30 秒かかりますが、DB への変更の保存には 30 分以上かかります。そして、sqlite 'disk or i/o error' で終了する前にクラッシュします

問題は、2 番目のプロセスでの挿入/更新が非常に遅いのはなぜですか? 彼らは同じ接続で同じデータベースの同じテーブルで作業しています。どちらの場合も、IStatelessSession が使用され、ado.batch_size は 1000 に設定されています。

どちらの場合も、コードは次のように更新されます。

BulkDataInsert((IStatelessSession session) =>
{
    foreach (Transaction t in transToInsert) { session.Insert(t); }
    foreach (Transaction t in transToUpdate) { session.Update(t); }
});

(ただし、最初のプロセスには挿入のみであるため、'transToUpdate' 行はありません。更新行を削除して挿入を行うだけでも、まだ約 10 分かかります。) transTo* 変数は、更新/挿入するオブジェクトを含むリストです。

BulkDataInsert はセッションを作成し、DB トランザクションを処理します。

4

2 に答える 2

0

この問題は、テストのセットアップが原因でした。nhibernate ベースのプロジェクトではよくあることですが、単体テストにはメモリ内の sqlite データベースを使用していました。これらはうまく機能しますが、欠点の 1 つは、セッションを閉じるとデータベースが破壊されることです。したがって、作業単位の実装には、セッションを維持し、必要なときに新しいトランザクションを作成するための「PreserveSession」プロパティが含まれています。

私の新しいパフォーマンス テストではディスク上のデータベースを使用していますが、テスト データベースの設定には共通のコードを使用しているため、PreserveSession を true に設定しています。

いくつかのセッションをすべて開いたままにしておくと (何もしていなくても)、しばらくするとパフォーマンスの低下やディスク IO エラーなどの問題が発生し始めるようです。

PreserveSession を false に設定して 2 番目のテストを再実行したところ、すぐに 30 分から 2 分未満になりました。これは、私が期待する場所です。

于 2012-12-20T10:24:44.333 に答える
0

2番目のプロセスがわかりませんでした。ただし、考慮すべき点がいくつかあります。

  1. テーブルにクラスター化インデックスまたは非クラスター化インデックスはありますか?
  2. ディスクドライブは何台ありますか?
  3. 2 番目のテストで DB に書き込みを行っているスレッドの数は?

ディスク、スレッド、インデックスなどを増やすことで解決できる IO ボトルネックが発生しているようです。

したがって、多くのことを想定すると、ここに私が「考えている」ことが起こっています。

  1. 最初のテストでは、テーブルにはおそらくインデックスがありません。データを挿入しているだけなので、特に 1 つのディスクに書き込んでいる場合は、かなり高速なシングル スレッドでの順次挿入になります。
  2. 2 番目のテストでは、データを読み取ってからデータを更新しています。SQL インスタンスは、更新する必要があるレコードを見つける必要があります。インデックスがない場合、この「検索」アクションは基本的にテーブル スキャンであり、80,000 行の更新ごとに実行されます。これにより、アプリケーションが非常に遅くなります。

おそらく最も簡単な方法は、テーブルにクラスター化インデックスを追加して一意のキーを作成することです。最適なオプションは、where 句で使用している列を使用してそれらの行を「更新」することです。

お役に立てれば。

免責事項:私はかなりの数の仮定をしました

于 2012-12-19T19:04:24.263 に答える