Entity Framework Core 3.0のパフォーマンスへの影響(コレクションナビゲーションプロパティを含む)(デカルト爆発)


8

EF Core 2.2をEF Core 3.0にアップグレードした後、大きなパフォーマンスの問題に直面しています。単一のコレクションナビゲーションプロパティと数百のフィールドを持つ単純なデータモデルを想像してみてください(現実はさらに暗く見えます)。

public class Item
{
  [Key]
  public int ItemID {get;set;}

  public ICollection<AddInfo> AddInfos {get;set;}
  ...  // consisting of another 100+ properties!
}

そして

public class AddInfo
{
  [Key]
  public int AddInfoID {get;set;}
  public int? ItemID {get;set;}
  public string SomePayload {get;set;}
}

アイテムの取得中、次のようにクエリを実行します。

...
var myQueryable = this._context.Items.Include(i => i.AddInfos).Where(**some filter**);
... // moar filters
var result = myQueryable.ToList();

この時点まで、まっすぐ進みます。

EF 2.2では、クエリ可能な結果を​​フェッチすることで、2つの個別のクエリ(1つItemAddInfo-レベル用)を取得します。これらのクエリは通常10.000 itemsと約250.000をフェッチしAddInfosます。

ただし、EF Core 3.0では、単一のクエリが生成されているため、 一見すると左側のクエリに結合AddInfoするItem方が適切なオプションのようです。私たちは、Itemしかし、なぜ小さいクラスまたは匿名型に投影しているすべての100+フィールド、(.Select(...)への呼び出しを追加する-法)に取得する必要が現実的ではありません。したがって、結果セットには冗長性があり(それぞれItem約25回)、クエリ自体が許容時間内に実行するには時間がかかりすぎます。

EF-Core 3.0 には、データモデル大幅に変更することなく、古き良きEF Core 2.2のクエリ動作に戻すことができるオプションがありますか?アプリケーションの他の部分でのこの変更からすでに利益を得ていますが、この特定のシナリオでは利益がありません。

よろしくお願いします!

更新

さらなる調査の後、私は、この問題は既にマイクロソフトでadressedされることを見出し、ここで、箱のうち、分割されたクエリの実行を設定する方法はないように思えます。


クエリはWeb接続(http)経由ですか?Core 2.2とCore 3.0では、デフォルトのヘッダーが異なる場合があります(httpバージョン1.0やhttpバージョン1.1など)。WiresharkやFiddlerなどのスニファを使用して、最初のリクエストをチェックし、ヘッダーが同じであることを確認することができます。
jdweng

1
この警告をお読みください。動作は変更され、古いEF 6.xの動作と一致しています。私が理解できないことEF 2.2はそれを2つのクエリに変換する方法でした。そのためのサンプルはありますか?
Eldar、

@Eldar、リンクを提供していただきありがとうございます。同じフィルター(-> WHERE-Clause)がItemテーブルとAddInfoテーブルからデータをフェッチするために使用されたので、2つのクエリへの変換が可能になりました。EFは、アイテムとそれらのコレクションナビゲーションプロパティをメモリに結合しました。
TheSchmu

回答:


3

私の最初の質問の更新によると、洞察は私自身が現在のものであることを保証するために行ったものであり、実際には分割クエリの実行に戻るための組み込みの構成はありません。

ただし、MSは、最小限のコード変更(これはユースケース用です)これを行う方法のコードサンプルをここに提供しています

コレクションナビゲーションプロパティへの.Include(...)呼び出しを削除するだけです(この場合、1:nリレーション、1:1リレーションは影響を受けません!)。アイテムを取得した後、次のコードを使用して呼び出しを行います。

...
var myQueryable = this._context.Items.Where(**some filter**);
... // moar filters
var result = myQueryable.ToList();
...
var addInfos = myQueryable.Include(x => x.AddInfos).SelectMany(x => x.AddInfos).Select(x => new {x.ItemID, x}).ToList();

これにより、コレクションナビゲーションプロパティエンティティがフェッチされ、変更追跡が有効になっている場合は、result変数内の個々のアイテムのコレクションが自動的に入力されます。


2番目のクエリの出力(生成されたSQLクエリ)も共有できますか?
Eldar
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.