複数のデバイスからの 1 秒あたり 500 の測定値を保存する必要があります。各測定値は、タイムスタンプ、数量タイプ、およびいくつかのベクトル値で構成されます。現在、測定ごとに 8 つのベクトル値があり、この数はプロトタイプ プロジェクトのニーズに対して一定であると見なすことができます。HNibernate を使用しています。テストは SQLite (メモリ内ではなくディスク ファイル db) で行われますが、本番環境はおそらく MsSQL になります。
Measurement エンティティ クラスは、単一の測定値を保持するもので、次のようになります。
public class Measurement
{
public virtual Guid Id { get; private set; }
public virtual Device Device { get; private set; }
public virtual Timestamp Timestamp { get; private set; }
public virtual IList<VectorValue> Vectors { get; private set; }
}
ベクトル値は個別のテーブルに格納されるため、それぞれが外部キーを介して親の測定値を参照します。
生成された SQL が (合理的に) 効率的であることを確認するために、いくつかのことを行いました。ID の生成に Guid.Comb を使用し、1 回のトランザクションで約 500 項目をフラッシュし、ADO.Net バッチ サイズを 100 に設定しますSQLIte はバッチ更新をサポートしていないと思いますか? しかし、後で役に立つかもしれません)。
問題
現在、1 秒あたり 150 ~ 200 の測定値を挿入できます (これは十分な速度ではありませんが、これは私たちが話している SQLite です)。生成された SQL を見ると、(予想どおり) 単一のトランザクションに挿入されていることがわかります。
- 1 タイムスタンプ
- 1回の測定
- 8 つのベクトル値
これは、実際には 10 倍以上の単一テーブルの挿入を行っていることを意味します: 1 秒あたり 1500 ~ 2000 です。
すべて (8 つのベクトル値すべてとタイムスタンプ) を測定テーブルに配置すると (9 つの専用列を追加)、挿入速度を最大 10 倍に上げることができるようです。
SQLサーバーに切り替えるとパフォーマンスが向上しますが、現在のデータベースの編成方法に関連する不要なパフォーマンス コストを回避する方法があるかどうかを知りたい.
[編集]
インメモリ SQLite では、約 350 アイテム/秒 (3500 の単一テーブル挿入) が得られます。これは、NHibernate で得られるものとほぼ同じであると考えています (この投稿を参考にしてください: http://ayende.com/Blog/archive/ 2009/08/22/nhibernate-perf-tricks.aspx )。
しかし、SQL サーバーに切り替えて、物事を想定するのをやめたほうがよいのではないでしょうか。テストしたらすぐに記事を更新します。
[アップデート]
私は SQL サーバーに移行し、階層を平坦化しました。3000 回/秒の測定値を数時間保存してテストしたところ、問題なく動作しているようです。