Auswirkungen auf die Leistung von Entity Framework Core 3.0 beim Einbeziehen von Sammlungsnavigationseigenschaften (kartesische Explosion)

8

Nach dem Upgrade von EF Core 2.2 auf EF Core 3.0 ist ein großes Leistungsproblem aufgetreten. Stellen Sie sich ein einfaches Datenmodell mit einer einzigen Sammlungsnavigationseigenschaft und Hunderten von Feldern vor (die Realität sieht noch dunkler aus):

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

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

und

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

Während des Abrufs von Elementen werden folgende Abfragen durchgeführt:

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

Bis zu diesem Punkt geradeaus.

In EF 2.2 führt das Abrufen dieser abfragbaren Datei zu zwei separaten Abfragen, eine für Itemund eine für die AddInfoEbene. Diese Abfragen holen normalerweise 10.000 itemsund ungefähr 250.000 ab AddInfos.

In EF - Core 3.0 jedoch eine einzelne Abfrage generiert wird, links Beitritt AddInfozu , Item dass auf den ersten Blick erscheint die bessere Option zu sein. Unser ItemFeld muss jedoch mit allen über 100 Feldern abgerufen werden, weshalb eine Projektion auf eine kleinere Klasse oder einen anonymen Typ (Hinzufügen eines Aufrufs zur .Select (...) - Methode) nicht möglich ist. Daher enthält die Ergebnismenge so viel Redundanz (jeweils Itemca. 25 Mal), dass die Abfrage selbst zu lange dauert, um in einer akzeptablen Zeit ausgeführt zu werden.

Bietet EF-Core 3.0 eine Option, mit der wir ohne umfangreiche Änderungen an unserem Datenmodell zum Abfrageverhalten des guten alten EF Core 2.2 zurückkehren können ? Wir profitieren bereits von dieser Änderung in anderen Teilen der Anwendung, jedoch nicht in diesem speziellen Szenario.

Vielen Dank im Voraus!

Aktualisieren

Nach weiteren Untersuchungen stellte ich fest, dass dieses Problem hier bereits bei Microsoft behoben wurde und es keine Möglichkeit gibt, die Ausführung der geteilten Abfrage zu konfigurieren.

TheSchmu
quelle
Ist die Abfrage über eine Webverbindung (http)? Die Standardheader können in Core 2.2 und Core 3.0 unterschiedlich sein (wie http Version 1.0 und http Version 1.1). Möglicherweise möchten Sie einen Sniffer wie Wireshark oder Fiddler verwenden und die erste Anforderung überprüfen, um sicherzustellen, dass die Header identisch sind.
JDWeng
1
Lesen Sie diese Warnung . Sie haben Recht, das Verhalten wird geändert, es stimmt mit dem alten EF 6.x-Verhalten überein. Was ich nicht verstehen kann Wie war EF 2.2 hat es in nur 2 Abfragen übersetzt. Haben Sie Proben dafür?
Eldar
@Eldar, danke für die Bereitstellung des Links. Die Übersetzung in zwei Abfragen wurde ermöglicht, da derselbe Filter (-> WHERE-Klausel) zum Abrufen von Daten aus der Item- und AddInfo-Tabelle verwendet wurde, wobei letztere natürlich mit einem Join zurück zur Item-Tabelle selbst durchgeführt wurden. EF hat die Elemente und ihre Sammlungsnavigationseigenschaften im Speicher wieder zusammengefügt.
TheSchmu

Antworten:

3

Nach dem Update meiner ersten Frage gingen die Erkenntnisse so weit, dass ich mir sicher war, dass es derzeit keine integrierte Konfiguration gibt, um zur Ausführung der geteilten Abfrage zurückzukehren.

MS hat hier jedoch Codebeispiele bereitgestellt, wie dies mit minimalen Codeänderungen (für unseren Anwendungsfall!) Zu tun ist .

Wir entfernen einfach die .Include (...) -Aufrufe für Sammlungsnavigationseigenschaften (1: n-Beziehungen in unserem Fall, 1: 1-Beziehungen sind nicht betroffen!). Nach dem Abrufen der Elemente tätigen wir einfach einen weiteren Anruf mit:

...
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();

Dadurch werden die Entitäten der Sammlungsnavigationseigenschaften abgerufen und - wenn die Änderungsverfolgung aktiviert ist - automatisch die Sammlungen für die einzelnen Elemente in der resultVariablen gefüllt.

TheSchmu
quelle
Können Sie auch die Ausgabe (generierte SQL-Abfrage) der zweiten Abfrage freigeben?
Eldar