質問: _db.DataPoints.AsNoTracking().ToArray(); ``` AsNoTracking()を使用しないと、時間がかかります。 DataPointは、いくつかのプリミティブプロパティを持つ小さなPOCOです。私がロードしているデータの総量は4.5メガバイトです。 ``` public class DataPointDto { [Key] public ulong Id { get; set; } [Required] public DateTimeOffset TimeStamp { get; set; } [Required] public bool trueTime { get; set; } [Required] public double Value { get; set; } } ``` **質問:**この多くのオブジェクトをロードするには、より良い方法がありますか、それともこのレベルのパフォーマンスに固執していますか? **楽しい事実:** x86は11秒、x64は18秒かかる。「コードの最適化」は1秒ごとに減少する。 Asyncを使用すると、実行時間が30秒に短縮されます。
回答: ほとんどの回答は少ないデータを読み込むという共通の知恵に従いますが、ここでは**絶対的に積極的に**多くのエンティティを読み込む**必要があり**ます。それではどうやってやるの? **パフォーマンスの低下の原因** この操作がこれほど長くかかるのは避けられないことですか?まあ、そうではありません。ディスクからわずか1メガバイトのデータをロードしていますが、パフォーマンスが低下する原因は、データが40,000個の小さなエンティティに分割されているためです。データベースはそれを扱うことができますが、エンティティフレームワークはこれらのエンティティの設定やトラッキングの変更などに苦労しているようです。データを変更するつもりがなければ、できることはたくさんあります。 私は3つのことを試みた ### プリミティブ プロパティを1つだけロードすると、プリミティブのリストが得られます。 ``` List dataPoints = _db.DataPoints.Select(dp => dp.Value).ToList(); ``` これは、エンティティフレームワークによって通常実行されるエンティティ作成のすべてをバイパスします。このクエリには0.4秒かかりましたが、元のクエリでは18秒でした。我々は**45(!)**倍の改善を話している。 ### 匿名の種類 当然のことながら、多くの場合、プリミティブの配列だけでなく、LINQクエリの中に新しいオブジェクトを作成することができます。エンティティフレームワークは通常のエンティティを作成せず、操作ははるかに高速に実行されます。利便性のために匿名オブジェクトを使用できます。 ``` var query = db.DataPoints.Select(dp => new {Guid ID = dp.sensorID, DateTimeOffset Timestamp = dp.TimeStamp, double Value = dp.Value}); ``` この操作には、通常は同じ量のデータを取得するのに18秒と比較して1.2秒かかります。 ### タプル 私のケースでは、匿名型の代わりにタプルを使用すると、パフォーマンスが少し向上することがわかりました。次のクエリは約30%速く実行されました。 ``` var query = db.DataPoints.Select(dp => Tuple.Create(dp.sensorID, dp.TimeStamp, dp.Value)); ``` ### 他の方法 1. LinQクエリ内で構造体を使用することはできないため、これはオプションではありません 2. 多くの場合、多数のレコードを結合して、多数の個別レコードを取得する際のオーバーヘッドを減らすことができます。少ないレコードを検索することで、パフォーマンスを向上させることができます。例えば、私のusecaseでは、私は5分毎に24/7を取っているいくつかの測定値を持っています。現時点では私はそれらを個別に保管しており、それは愚かです。誰もそれらの1日分未満の質問をすることはありません。変更を加えてパフォーマンスがどのように変化したかを調べるときにこの記事を更新する予定です。 3. オブジェクト指向のDBまたはマイクロORMを使用することをお勧めします。私はどちらも使用していないので、私はコメントすることはできません。