EF7とSQLiteで1000個のオブジェクトを読み込む方法

c# entity-framework-core sqlite win-universal-app

質問

私はEF7でSQLite DBから40,000個の非常に小さなオブジェクトを読んでいますが、18秒かかるため、UWPアプリケーションでは長すぎます。これが起こると、単一コアのCPU使用率は100%に達しますが、ディスク読み取り速度は1%前後になります。

var dataPoints =  _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<double> 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を使用することをお勧めします。私はどちらも使用していないので、私はコメントすることはできません。

人気のある回答

別のテクニックを使ってすべてのアイテムを読み込むことができます。

ユーザーがListViewをスクロールしている間にデータの一部をロードする独自のロジックを作成することができます(私はそれを使用していると思います)。

幸いにもUWPはこのテクニックを簡単に実行できます。インクリメンタルローディングについては、ドキュメントとサンプルを参照してください

https://msdn.microsoft.com/library/windows/apps/Hh701916



Related

ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ