11

複数のデバイスからの 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 回/秒の測定値を数時間保存してテストしたところ、問題なく動作しているようです。

4

10 に答える 10

10

個人的には、非正規化してから ETL プロセスを作成して、このデータを分析/通常の使用のためにより正規化された形式にすることをお勧めします。

基本的に理想的な状況は、データの取得を、処理する必要がある形式でのデータの取得とはまったく別の問題として扱う、別のデータベース (または、必要に応じて同じデータベース内の別のテーブル) を持つことです。それ。

これは、現在のデータベース構造の周りに作成したエンティティを破棄する必要があるという意味ではありません。非正規化されたテーブルも作成し、それらを取り込む ETL を作成する必要があるだけです。SSIS を使用することもできます (ただし、データを正規化された一連のテーブルに定期的に、または C# アプリやその他の一括読み込みプロセスに取り込む必要があります。

編集: もちろん、これは、分析をリアルタイムで行う必要がなく、データの収集のみを行うことを前提としています。多くの場合、分析データをリアルタイムで更新する必要はありません (また、実際には更新したくない場合もあります)。これは紙の上では良さそうに見えますが、実際には必要のないことの 1 つです。

このデータを分析する一部の人々がリアルタイム アクセスを必要とする場合、必要に応じて「ベア メタル」の非正規化トランザクション データに対してツールセットを構築できます。場合によっては、より静的なデータセットを使用することを好むでしょう!): その場合、定期的な ETL は非常にうまく機能します。ターゲット ユーザーと集まって、彼らが本当に必要としているものを見つけるだけです。

于 2010-05-03T11:16:41.833 に答える
4

まあ、それは依存するでしょう。8 つのベクトル値は、決して変化しない堅実な数ですか? 次に、ケースでの非正規化が理にかなっている可能性があります(ただし、使用している実際のハードウェアとデータベースでテストするだけでわかります)。来週9回の測定になる可能性がある場合は、実行しないでください。

何をすべきかを決める前に、まず SQL サーバーと実行する機器に切り替える必要があると思います。

実行プロファイラーを切り替えたら。nHibernate が挿入に最適なパフォーマンスの SQl を作成していない可能性は十分にあります。

おそらく挿入時に分割されている一連のベクトルがあるという事実は、パフォーマンスの問題の一部である可能性があります。分割しなければならないセットよりも、8 つの個別の変数を使用する方がよい場合があります。

1 日に 4,000 万件を超えるレコードについて話しているとします。これには、いくつかの主要なハードウェアと非常によく設計されたデータベースが必要になります。また、リレーショナル データベースがこれに最適な選択ではない可能性もあります (この量のデータをどのように使用したいのかわかりません)。このデータをどれくらいの期間保持していますか。このサイズはすぐに手に負えなくなります。

グループ内のレコードを 1 分に 1 回一括挿入することはできますか? 一括挿入は、行ごとの挿入よりもはるかに高速です。

設計では、データを挿入するだけでなく、データをどのように使用するかを考慮する必要があります。一般に、挿入を高速化するために行うことは、選択を遅くする可能性があり、その逆も同様です。分析のために 1 日に 1 回ロードされるデータ ウェアハウスが必要になる場合があります (および 2 番目のデータまで生データを表示できるようにするためのクイック クエリ)。

于 2010-05-03T17:55:37.797 に答える
3

まず、ターゲット データベースに移動します。SqlLite に基づくパフォーマンスは、MsSql に基づくパフォーマンスを示すものではない場合があります

次に、パフォーマンスのボトルネックがどこにあるかを測定します。率直に言って、それはディスクであり、メモリ内データベースの方がはるかに優れたパフォーマンスを発揮すると思います。

次に、必要に応じて、上記で提案した ETL プロセスを使用して非正規化します。

イベントストリーム処理には、「ディスクにヒットしたら死ぬ」という格言があります。 ;-)

于 2010-05-03T11:38:32.290 に答える
2

SqlBulkCopyの使用を検討しましたか?それは本当に速く動作します。私はこれを実稼働環境で使用し、SQLServer2005マシンを使用して1秒未満で1つのテーブルに10.000以上の挿入を達成しました。アプリケーションに一括挿入するDataTableを準備する必要があります。これがサンプルです。

        public static void SQLBulkCopyInsert(DataTable dtInsertRows, string destinationTableName, string[] columnMappings)
    {
        using (SqlBulkCopy sbc = new SqlBulkCopy(DBHelper.Secim2009DB.ConnectionString, SqlBulkCopyOptions.UseInternalTransaction))
        {                
            sbc.DestinationTableName = destinationTableName;
            // Number of records to be processed in one go
            sbc.BatchSize = 30000;
            // Map the Source Column from DataTabel to the Destination Columns in SQL Server 2005 Person Table

            foreach (string columnMapping in columnMappings)
            {
                sbc.ColumnMappings.Add(columnMapping, columnMapping);
            }

            // Number of records after which client has to be notified about its status
            sbc.NotifyAfter = dtInsertRows.Rows.Count;
            // Event that gets fired when NotifyAfter number of records are processed.
            sbc.SqlRowsCopied += new SqlRowsCopiedEventHandler(sbc_SqlRowsCopied);
            // Finally write to server
            sbc.WriteToServer(dtInsertRows);
            sbc.Close();
        }
    }

    public static void sbc_SqlRowsCopied(object sender, SqlRowsCopiedEventArgs e)
    {            

    }
于 2010-05-05T14:00:19.180 に答える
1

"We have a requirement to store 500 measurements per second, coming from several devices."

Don't use DBMS's to store that kind of data.

What are the reasons people use DBMS's ?

(a) They can enforce constraints for you on the data you are trying to register. But you don't have any. The measurements data are what they are and they need to be accepted. No constraints.

(b) They can ensure consistency and integrity of your precious business data in the case of (1) constraint violations and (2) severe system failures such as disk I/O errors. But since you don't have constraints, (1) doesn't apply. And as for (2), what would you do with your measurements if a disk I/O error prevents it from being recorded ? Your measurements are lost no matter what.

So imo, you don't have any reason what so ever to use a DBMS. Dump your load of measurements in a flat file and process that as needed.

于 2010-05-03T20:48:38.567 に答える
1

「なぜ正規化するのか」と自問する必要があります。

主な理由は3つあります。

  1. データの一貫性
  2. 更新速度
  3. サイズ

データの一貫性

ドロップダウンと、同じFKを持つ同じものを意味するすべての行があるのはいいですね。かなり明白。これは、複数のデータ「エディター」を持つDBにとって非常に重要です。しかし、これは私たちのプロセスと同じくらい良いだけです。フライトデータベースであり、ワシントンDCの国立空港のエントリがあるとします...ワシントンDCのレーガン国立空港の新しいエントリを追加するものもあります... FKはそこにあり、子供用テーブルで使用されますが、勝ちましたそれほど価値はありません...しかし、そうすることはまだ良いことです...

更新速度

やるべきことは、国立空港の行を新しい名前で更新することです。親行が1つしかないため、非常に簡単な変更になります。フライトテーブルにテキストが含まれているとしたら、何百万もの行を更新していたでしょう。

サイズ

すべてのレコードに「レーガン国立空港」を保存した場合、たとえば19のFKよりも多くのスペースが必要になります。以前はサイズが非常に重要でしたが、SANではまったく関係ありません。


結論

さて、あなたはあなたのSOLOデータ収集アプリが楽器の名前をまっすぐに保つことができないのではないかと心配していますか?データの一貫性が課題になるのでしょうか?

では、機器やデータポイントの名前を何回変更すると思いますか?つまり、溶存O2は溶存O2であり、濁度は濁度ですよね?ただし、一括更新を行う必要がある場合は、実行の間にダウンタイムが発生する可能性があります。したがって、これは問題ではありません。

わかりました、サイズ、確かに...それは多くの測定値です。しかし、「溶存酸素」の測定は行わないでください。DO2は問題ありません...「7」のような一部のFKよりもどれだけ大きいですか?時間を節約するためにスペースを費やしてください。

優れたデータベース設計者が行うことは常に言われているので、正規化しないでください。なぜあなたがそれをしているのか、そしてなぜあなたがあなたが選んでいるものを選んでいるのかを知ってください。

于 2010-05-04T14:36:35.820 に答える
1

他のデータベースの代替案を検討することもできます。MSSQL は多くの機能を提供しますが、オーバーヘッドが追加されます。

高パフォーマンス処理 (あなたがしようとしているものなど) に関する優れたリソースは、http://highscalability.com/にあります。

彼らが持っていたケース スタディの 1 つは、何千ものデバイス統計をデータベースに保存することです。解決策は、複数の MYSQL データベースであり、デバイス ID に基づいてリクエストをルーティングしました。全体的に - このサイトは優れたケース スタディを提供できます。そこに可能な解決策を見つけることができるかもしれません。

ティムール

于 2010-05-04T01:40:16.317 に答える
1

適切な DBMS とハードウェアを使用してください。ハードウェアが異なる別のプラットフォームでテストしても、パフォーマンスについては何もわかりません。

非正規化は、定義上、冗長なデータを作成していることを意味するため、書き込みのパフォーマンスに役立つ可能性は低く、したがって、書き込みごとに行う作業は少なくなるのではなく、多くなります。

あなたが引用した数値は、ストリーミング データのシナリオでは例外的ではなく、適切なハードウェアを使用して完全に達成可能ですが、nHibernate はあなたにとって大きな制限要因になると思います. nHib がこの種のことに対して賢明な選択である可能性は低いと思います。

ストリーミング データ ソースと CEP に特別なサポートを提供するテクノロジの使用を検討しましたか? 例: OSISoft PI、Microsoft StreamInsight、および SQL Server のファイル ストリーム機能。

于 2010-05-04T10:20:45.913 に答える
1

非正規化しないでください。便利なデザイン パターンを使用して、結果をデザインします。パフォーマンスに役立つ設計パターンが、正規化規則に従って得られるものとは異なる設計になる場合があります。

非正規化によってあなたの状況が改善されるとは思いません。非正規化を支持するほとんどすべての人々は、新しいデータを保存しているときにはパフォーマンスが向上しないと言っています。それらは、データを取得するときに発生します。それがあなたのケースにどのように適用されるかを考え出す必要があります。

ここまで言えます。複数の同時プロセスを介して格納することになる場合、設計は深刻なボトルネックになり、正規化された設計よりも実行が遅くなる可能性があります。

しかし、私の言葉を鵜呑みにしないでください。実験。分析します。学び。繁栄します。

于 2010-05-03T11:18:06.380 に答える
0

はい。非正規化(データのフラット化)と時間によるデータのチャンク化の両方によって、挿入のオーバーヘッドを削減することを検討します。各レコードがデバイスごとに1秒に相当するデータを格納するようにデータベースを設計します。

public class Measurement 
{ 
    public Guid ID { get; private set; } 
    public Device Device { get; private set; }
    public Sample[] { get; private set; }

    public DateTime FirstTimestamp { get; private set; } 
    public DateTime LastTimestamp { get; private set; } 
} 

public class Sample
{ 
    public DateTime Timestamp { get; private set; } 
    public VectorValue[] Vectors { get; private set; } 
}

複雑なタイプ(この場合はリストのリストなど)を単一のレコードに格納するには、さまざまな方法があります。XML列CLRユーザー定義型は2つの例です。

于 2010-05-03T14:31:18.927 に答える