Teilen über


Überlegungen zur Leistung (Entity Framework)

In diesem Thema werden die Leistungsmerkmale des ADO.NET Entity Framework beschrieben und einige Überlegungen zur Verbesserung der Leistung von Entity Framework-Anwendungen erläutert.

Phasen der Abfrageausführung

Um die Leistung von Abfragen im Entity Framework besser zu verstehen, ist es hilfreich, die Vorgänge zu verstehen, die auftreten, wenn eine Abfrage für ein konzeptionelles Modell ausgeführt wird und Daten als Objekte zurückgibt. In der folgenden Tabelle werden diese Reihe von Vorgängen beschrieben.

Vorgang Relative Kosten Frequenz Kommentare
Laden von Metadaten Mäßig Einmal in jeder Anwendungsdomäne. Modell- und Zuordnungsmetadaten, die vom Entity Framework verwendet werden, werden in einem MetadataWorkspace geladen. Diese Metadaten werden global zwischengespeichert und stehen anderen Instanzen ObjectContext in derselben Anwendungsdomäne zur Verfügung.
Öffnen der Datenbankverbindung Moderat1 Bei Bedarf. Da eine offene Verbindung mit der Datenbank eine wertvolle Ressource verbraucht, wird das Entity Framework geöffnet und schließt die Datenbankverbindung nur bei Bedarf. Sie können die Verbindung auch explizit öffnen. Weitere Informationen finden Sie unter Verwalten von Verbindungen und Transaktionen.
Generieren von Sichten Hoch Einmal in jeder Anwendungsdomäne. (Kann vorgeneriert werden.) Bevor das Entity Framework eine Abfrage für ein konzeptionelles Modell ausführen oder Änderungen an der Datenquelle speichern kann, muss eine Reihe lokaler Abfrageansichten generiert werden, um auf die Datenbank zuzugreifen. Aufgrund der hohen Kosten für die Generierung dieser Ansichten können Sie die Ansichten vorab generieren und dem Projekt zur Entwurfszeit hinzufügen. Weitere Informationen finden Sie unter Gewusst wie: Vorgenerieren von Ansichten zur Verbesserung der Abfrageleistung.
Vorbereiten der Abfrage Moderat2 Einmal für jede eindeutige Abfrage. Umfasst die Kosten für das Verfassen des Abfragebefehls, das Generieren einer Befehlsstruktur basierend auf Modell- und Zuordnungsmetadaten und das Definieren der Form der zurückgegebenen Daten. Da jetzt sowohl Entity SQL-Abfragebefehle als auch LINQ-Abfragen zwischengespeichert werden, nehmen spätere Ausführung derselben Abfrage weniger Zeit in Anspruch. Sie können weiterhin kompilierte LINQ-Abfragen verwenden, um diese Kosten in späteren Ausführungen zu reduzieren und kompilierte Abfragen effizienter zu sein als LINQ-Abfragen, die automatisch zwischengespeichert werden. Weitere Informationen finden Sie unter Kompilierte Abfragen (LINQ to Entities).For more information, see Compiled Queries (LINQ to Entities). Allgemeine Informationen zur AUSFÜHRUNG von LINQ-Abfragen finden Sie unter LINQ to Entities. Anmerkung: LINQ to Entities-Abfragen, die den Enumerable.Contains Operator auf In-Memory-Sammlungen anwenden, werden nicht automatisch zwischengespeichert. Das Parametrisieren von In-Memory-Auflistungen in kompilierten LINQ-Abfragen ist ebenfalls nicht zulässig.
Ausführen der Abfrage Niedrig2 Einmal für jede Abfrage. Die Kosten für die Ausführung des Befehls gegen die Datenquelle unter Verwendung des ADO.NET-Datenproviders. Da die meisten Datenquellen Abfragepläne zwischenspeichern, kann die spätere Ausführung derselben Abfrage noch weniger Zeit in Anspruch nehmen.
Laden und Überprüfen von Typen Niedrig3 Einmal für jede ObjectContext Instanz. Typen werden geladen und anhand der Typen überprüft, die vom konzeptionellen Modell definiert werden.
Nachverfolgung Niedrig3 Einmal für jedes Objekt, das eine Abfrage zurückgibt. 4 Verwendet eine Abfrage die NoTracking-Mergeoption, wird die Leistung in dieser Phase nicht beeinträchtigt.

Wenn bei der Abfrage die Optionen AppendOnly, PreserveChanges oder OverwriteChanges zum Zusammenführen verwendet werden, werden die Abfrageergebnisse im ObjectStateManager nachverfolgt. Für jedes von der Abfrage zurückgegebene verfolgte Objekt wird ein EntityKey generiert, das für die Erstellung eines ObjectStateEntry im ObjectStateManager verwendet wird. Wenn ein vorhandenes ObjectStateEntry Objekt für das EntityKeygefunden werden kann, wird das vorhandene Objekt zurückgegeben. Wenn die PreserveChanges- oder OverwriteChanges-Option verwendet wird, wird das Objekt aktualisiert, bevor es zurückgegeben wird.

Weitere Informationen finden Sie unter Identitätsauflösung, Zustandsverwaltung und Änderungsnachverfolgung.
Materialisieren der Objekte Moderat3 Einmal für jedes Objekt, das eine Abfrage zurückgibt. 4 Der Prozess des Lesens des zurückgegebenen DbDataReader Objekts und das Erstellen von Objekten und Festlegen von Eigenschaftswerten, die auf den Werten in jeder Instanz der DbDataRecord Klasse basieren. Wenn das Objekt bereits in der ObjectContext Abfrage vorhanden ist und die Abfrage die AppendOnly Oder PreserveChanges Zusammenführungsoptionen verwendet, wirkt sich diese Phase nicht auf die Leistung aus. Weitere Informationen finden Sie unter Identitätsauflösung, Zustandsverwaltung und Änderungsnachverfolgung.

1 Wenn ein Datenquellenanbieter verbindungspooling implementiert, werden die Kosten für das Öffnen einer Verbindung über den Pool verteilt. Der .NET-Anbieter für SQL Server unterstützt verbindungspooling.

2 Kosten steigen mit erhöhter Abfragekomplexität.

3 Die Gesamtkosten werden proportional zur Anzahl der von der Abfrage zurückgegebenen Objekte erhöht.

4 Dieser Aufwand ist für EntityClient-Abfragen nicht erforderlich, da EntityClient-Abfragen anstelle EntityDataReader von Objekten zurückgeben. Weitere Informationen finden Sie unter EntityClient-Anbieter für das Entity Framework.

Weitere Überlegungen

Es folgen weitere Überlegungen, die sich auf die Leistung von Entity Framework-Anwendungen auswirken können.

Abfrageausführung

Da Abfragen ressourcenintensiv sein können, überlegen Sie, an welchem Punkt in Ihrem Code und auf welchem Computer eine Abfrage ausgeführt wird.

Verzögerte und sofortige Ausführung

Wenn Sie eine ObjectQuery<T> ODER LINQ-Abfrage erstellen, wird die Abfrage möglicherweise nicht sofort ausgeführt. Die Abfrageausführung wird zurückgestellt, bis die Ergebnisse erforderlich sind, z. B. während einer foreach (C#)- oder For Each (Visual Basic)-Aufzählung oder wenn sie zum Ausfüllen einer List<T> Auflistung zugewiesen ist. Die Abfrageausführung beginnt sofort, wenn Sie die Execute-Methode für eine ObjectQuery<T> oder eine LINQ-Methode aufrufen, die eine Singleton-Abfrage zurückgibt, z. B. First oder Any. Weitere Informationen finden Sie unter Objektabfragen und Abfrageausführung (LINQ to Entities).

Clientseitige Ausführung von LINQ-Abfragen

Obwohl die Ausführung einer LINQ-Abfrage auf dem Computer auftritt, auf dem die Datenquelle gehostet wird, können einige Teile einer LINQ-Abfrage auf dem Clientcomputer ausgewertet werden. Weitere Informationen finden Sie im Abschnitt zur Speicherausführung unter Ausführen von Abfragen (LINQ to Entities).

Abfrage- und Zuordnungskomplexität

Die Komplexität einzelner Abfragen und der Zuordnung im Entitätsmodell wirkt sich erheblich auf die Abfrageleistung aus.

Zuordnungskomplexität

Modelle, die komplexer sind als eine einfache 1:1-Zuordnung zwischen Entitäten im konzeptionellen Modell und Tabellen im Speichermodell generieren komplexere Befehle als Modelle, die eine 1:1-Zuordnung aufweisen.

Abfragekomplexität

Abfragen, die eine große Anzahl von Verknüpfungen in den Befehlen erfordern, die für die Datenquelle ausgeführt werden oder die eine große Datenmenge zurückgeben, können die Leistung auf folgende Weise beeinträchtigen:

  • Abfragen für ein konzeptionelles Modell, das einfach erscheinen, können dazu führen, dass komplexere Abfragen für die Datenquelle ausgeführt werden. Dies kann vorkommen, da das Entity Framework eine Abfrage anhand eines konzeptionellen Modells in eine entsprechende Abfrage für die Datenquelle übersetzt. Wenn ein einzelner Entitätssatz im konzeptionellen Modell mehreren Tabellen in der Datenquelle zugeordnet ist oder eine Beziehung zwischen Entitäten einer Verknüpfungstabelle zugeordnet ist, kann der Abfragebefehl, der für die Datenquellenabfrage ausgeführt wird, mindestens eine Verknüpfung erfordern.

    Hinweis

    Verwenden Sie die ToTraceString Methode der ObjectQuery<T> Klassen, EntityCommand um die Befehle anzuzeigen, die für die Datenquelle für eine bestimmte Abfrage ausgeführt werden. Weitere Informationen finden Sie unter How to: View the Store Commands.

  • Geschachtelte Entity SQL-Abfragen können Verknüpfungen auf dem Server erstellen und eine große Anzahl von Zeilen zurückgeben.

    Nachfolgend sehen Sie ein Beispiel für eine geschachtelte Abfrage in einer Projektionsklausel:

    SELECT c, (SELECT c, (SELECT c FROM AdventureWorksModel.Vendor AS c  ) As Inner2
        FROM AdventureWorksModel.JobCandidate AS c  ) As Inner1
        FROM AdventureWorksModel.EmployeeDepartmentHistory AS c
    

    Außerdem bewirken solche Abfragen, dass die Abfragepipeline eine einzelne Abfrage durch die Verdoppelung von Objekten in geschachtelten Abfragen generiert. Aus diesem Gründen kann eine einzelne Spalte mehrmals dupliziert werden. In einigen Datenbanken, einschließlich SQL Server, kann dies dazu führen, dass die TempDB-Tabelle sehr groß wird, wodurch die Serverleistung verringert werden kann. Achten Sie darauf, wenn Sie geschachtelte Abfragen ausführen.

  • Alle Abfragen, die eine große Datenmenge zurückgeben, können zu einer verringerten Leistung führen, wenn der Client Vorgänge ausführt, die Ressourcen auf eine Weise nutzen, die proportional zur Größe des Resultsets ist. In solchen Fällen sollten Sie die Menge der von der Abfrage zurückgegebenen Daten einschränken. Weitere Informationen finden Sie unter Vorgehensweise: Blättern durch Abfrageergebnisse.

Alle vom Entity Framework automatisch generierten Befehle sind möglicherweise komplexer als ähnliche Befehle, die explizit von einem Datenbankentwickler geschrieben wurden. Wenn Sie explizite Kontrolle über die Befehle benötigen, die für Ihre Datenquelle ausgeführt werden, sollten Sie eine Zuordnung zu einer Tabellenwertfunktion oder einer gespeicherten Prozedur definieren.

Beziehungen

Um eine optimale Abfrageleistung zu erzielen, müssen Sie Beziehungen zwischen Entitäten sowohl als Zuordnungen im Entitätsmodell als auch als logische Beziehungen in der Datenquelle definieren.

Abfragepfade

Standardmäßig werden bei der Ausführung eines ObjectQuery<T> keine verwandten Objekte zurückgegeben (aber Objekte, die die Beziehungen selbst darstellen, werden zurückgegeben). Sie können verwandte Objekte auf eine von drei Arten laden:

  1. Legen Sie den Abfragepfad fest, bevor der ObjectQuery<T> Abfragepfad ausgeführt wird.

  2. Rufen Sie die Load-Methode für das Navigationsattribut auf, das das Objekt bereitstellt.

  3. Stellen Sie die Option LazyLoadingEnabled auf dem ObjectContext auf true. Beachten Sie, dass dies automatisch erfolgt, wenn Sie Objektebenencode mit dem Entity Data Model Designer generieren. Weitere Informationen finden Sie unter "Übersicht über generierten Code".

Wenn Sie überlegen, welche Option Sie verwenden möchten, beachten Sie, dass es einen Kompromiss zwischen der Anzahl der Anforderungen für die Datenbank und der Menge der in einer einzelnen Abfrage zurückgegebenen Daten gibt. Weitere Informationen finden Sie unter Laden verwandter Objekte.

Verwenden von Abfragepfaden

Abfragepfade definieren das Diagramm von Objekten, die eine Abfrage zurückgibt. Wenn Sie einen Abfragepfad definieren, ist nur eine einzelne Anforderung für die Datenbank erforderlich, um alle Objekte zurückzugeben, die der Pfad definiert. Die Verwendung von Abfragepfaden kann dazu führen, dass komplexe Befehle für die Datenquelle aus scheinbar einfachen Objektabfragen ausgeführt werden. Dies tritt auf, da mindestens eine Verknüpfung erforderlich ist, um verwandte Objekte in einer einzelnen Abfrage zurückzugeben. Diese Komplexität ist bei Abfragen für ein komplexes Entitätsmodell, wie beispielsweise eine Entität mit Vererbung oder einen Pfad, der Viele-zu-Viele-Beziehungen enthält, größer.

Hinweis

Verwenden Sie die ToTraceString-Methode, um den Befehl zu sehen, der von einem ObjectQuery<T> generiert wird. Weitere Informationen finden Sie unter How to: View the Store Commands.

Wenn ein Abfragepfad zu viele verwandte Objekte enthält oder die Objekte zu viele Zeilendaten enthalten, kann die Datenquelle die Abfrage möglicherweise nicht abschließen. Dies tritt auf, wenn für die Abfrage temporäre Zwischenspeicher erforderlich ist, der die Funktionen der Datenquelle überschreitet. In diesem Fall können Sie die Komplexität der Datenquellenabfrage verringern, indem Sie verwandte Objekte explizit laden.

Zum expliziten Laden verbundener Objekte muss die Load-Methode für eine Navigationseigenschaft aufgerufen werden, die eine EntityCollection<TEntity> oder EntityReference<TEntity> zurückgibt. Für das explizite Laden von Objekten wird jedes Mal eine Rundreise zur Datenbank erforderlich, wenn Load aufgerufen wird.

Hinweis

Wenn Sie Load aufrufen, während Sie eine Auflistung zurückgegebener Objekte durchlaufen, z. B. wenn Sie die foreach Anweisung (For Each in Visual Basic) verwenden, muss der Anbieter, der für die Datenquelle spezifisch ist, mehrere aktive Resultsets für eine einzelne Verbindung unterstützen. Für eine SQL Server-Datenbank müssen Sie einen Wert MultipleActiveResultSets = true in der Anbieterverbindungszeichenfolge angeben.

Sie können die LoadProperty Methode auch verwenden, wenn keine EntityCollection<TEntity> Oder EntityReference<TEntity> Eigenschaften für Entitäten vorhanden sind. Dies ist nützlich, wenn Sie POCO-Entitäten verwenden.

Obwohl das explizite Laden verwandter Objekte die Anzahl der Verknüpfungen reduziert und die Menge redundanter Daten verringert, Load müssen wiederholte Verbindungen mit der Datenbank benötigt werden, was beim expliziten Laden einer großen Anzahl von Objekten zu kostspielig werden kann.

Speichern von Änderungen

Wenn Sie die SaveChanges Methode für ein ObjectContext aufrufen, wird für jedes hinzugefügte, aktualisierte oder gelöschte Objekt im Kontext ein separater Befehl zum Erstellen, Aktualisieren oder Löschen generiert. Diese Befehle werden in der Datenquelle in einer einzelnen Transaktion ausgeführt. Wie bei Abfragen hängt die Leistung von Erstellungs-, Aktualisierungs- und Löschvorgängen von der Komplexität der Zuordnung im konzeptionellen Modell ab.

Verteilte Transaktionen

Vorgänge in einer expliziten Transaktion, die Ressourcen erfordern, die vom Verteilten Transaktionskoordinator (DTC) verwaltet werden, sind viel teurer als ein ähnlicher Vorgang, der die DTC nicht erfordert. Die Beförderung zum DTC erfolgt in den folgenden Situationen:

  • Eine explizite Transaktion mit einem Vorgang für eine SQL Server 2000-Datenbank oder andere Datenquellen, die ständig explizite Transaktionen auf den DTC hochstufen.

  • Eine explizite Transaktion mit einer Operation gegen SQL Server 2005, wenn die Verbindung vom Entity Framework verwaltet wird. Dies tritt auf, da SQL Server 2005 bei jedem Schließen der Verbindung und deren erneuten Öffnen innerhalb einer einzelnen Transaktion, was das Standardverhalten von Entity Framework darstellt, zu einem DTC wechselt. Beim SQL Server 2008 wird diese DTC-Höherstufung nicht durchgeführt. Um diese Heraufstufung bei Verwendung von SQL Server 2005 zu vermeiden, müssen Sie die Verbindung innerhalb der Transaktion explizit öffnen und schließen. Weitere Informationen finden Sie unter Verwalten von Verbindungen und Transaktionen.

Eine explizite Transaktion wird verwendet, wenn eine oder mehrere Vorgänge innerhalb einer System.Transactions Transaktion ausgeführt werden. Weitere Informationen finden Sie unter Verwalten von Verbindungen und Transaktionen.

Strategien zur Verbesserung der Leistung

Sie können die Gesamtleistung von Abfragen im Entity Framework verbessern, indem Sie die folgenden Strategien verwenden.

Vorabgenerieren von Sichten

Das Generieren von Ansichten basierend auf einem Entitätsmodell ist ein erheblicher Aufwand, wenn eine Anwendung eine Abfrage zum ersten Mal ausführt. Verwenden Sie das Hilfsprogramm EdmGen.exe, um Ansichten als Visual Basic- oder C#-Codedatei vorab zu generieren, die während des Entwurfs dem Projekt hinzugefügt werden können. Sie können auch das Textvorlagentransformations-Toolkit verwenden, um vorkompilierte Ansichten zu generieren. Vorgenerierte Ansichten werden zur Laufzeit überprüft, um sicherzustellen, dass sie mit der aktuellen Version des angegebenen Entitätsmodells konsistent sind. Weitere Informationen finden Sie unter Gewusst wie: Vorgenerieren von Ansichten zur Verbesserung der Abfrageleistung.

Bei der Arbeit mit sehr großen Modellen gilt die folgende Berücksichtigung:

Das .NET-Metadatenformat beschränkt die Anzahl von Benutzerzeichenfolgen in einer bestimmten Binärdatei auf 16.777.215 (0xFFFFFF). Wenn Sie Ansichten für ein sehr großes Modell generieren und die Ansichtsdatei diesen Größengrenzwert erreicht, erhalten Sie den Kompilierungsfehler "Kein logischer Leerraum übrig, um weitere Benutzerzeichenfolgen zu erstellen". Diese Größenbeschränkung gilt für alle verwalteten Binärdateien. Weitere Informationen finden Sie im Blog , in dem veranschaulicht wird, wie der Fehler beim Arbeiten mit großen und komplexen Modellen vermieden wird.

Erwägen Sie die Verwendung der NoTracking-Zusammenführungsoption für Abfragen.

Es ist ein Kostenaufwand erforderlich, um zurückgegebene Objekte im Objektkontext nachzuverfolgen. Wenn Sie Änderungen an Objekten erkennen und sicherstellen, dass mehrere Anforderungen für dieselbe logische Entität dieselbe Objektinstanz zurückgeben, müssen Objekte an eine ObjectContext Instanz angefügt werden. Wenn Sie nicht beabsichtigen, Aktualisierungen oder Löschungen an Objekten vorzunehmen und keine Identitätsverwaltung erforderlich zu machen, sollten Sie die NoTracking Zusammenführungsoptionen beim Ausführen von Abfragen in Betracht ziehen.

Zurückgeben der richtigen Datenmenge

In einigen Szenarien ist die Angabe eines Abfragepfads mit der Include Methode viel schneller, da weniger Roundtrips zur Datenbank erforderlich sind. In anderen Szenarien können jedoch zusätzliche Roundtrips zur Datenbank zum Laden verwandter Objekte schneller sein, da die einfacheren Abfragen mit weniger Verknüpfungen zu einer geringeren Redundanz von Daten führen. Aus diesem Gründen wird empfohlen, die Leistung verschiedener Methoden zum Abrufen verwandter Objekte zu testen. Weitere Informationen finden Sie unter Laden verwandter Objekte.

Um zu vermeiden, dass zu viele Daten in einer einzelnen Abfrage zurückgegeben werden, sollten Sie die Ergebnisse der Abfrage in verwaltbare Gruppen aufteilen. Weitere Informationen finden Sie unter Vorgehensweise: Blättern durch Abfrageergebnisse.

Einschränken des Gültigkeitsbereichs von ObjectContext

In den meisten Fällen sollten Sie eine ObjectContext Instanz in einer using Anweisung (Using…End Using in Visual Basic) erstellen. Dadurch kann die Leistung gesteigert werden, indem sichergestellt wird, dass die dem Objektkontext zugeordneten Ressourcen automatisch verworfen werden, wenn der Code den Anweisungsblock verlässt. Wenn Steuerelemente jedoch an Objekte gebunden sind, die vom Objektkontext verwaltet werden, sollte die ObjectContext Instanz beibehalten werden, solange die Bindung erforderlich ist und manuell verworfen wird. Weitere Informationen finden Sie unter Verwalten von Verbindungen und Transaktionen.

Erwägen Sie, die Datenbankverbindung manuell zu öffnen.

Wenn Ihre Anwendung eine Reihe von Objektabfragen ausführt oder häufig Aufrufe SaveChanges zum Speichern von Erstellungs-, Aktualisierungs- und Löschvorgängen an die Datenquelle ausführt, muss Entity Framework die Verbindung mit der Datenquelle kontinuierlich öffnen und schließen. In diesen Situationen sollten Sie die Verbindung zu Beginn dieser Vorgänge manuell öffnen und entweder schließen oder entsorgen, wenn die Vorgänge abgeschlossen sind. Weitere Informationen finden Sie unter Verwalten von Verbindungen und Transaktionen.

Leistungsdaten

Einige Leistungsdaten für das Entity Framework werden in den folgenden Beiträgen im ADO.NET Teamblog veröffentlicht:

Siehe auch