Freigeben über


Leistungsaspekte (Entity Framework)

In diesem Thema werden Leistungsmerkmale von ADO.NET Entity Framework beschrieben. Außerdem sind einige Vorschläge enthalten, die Sie zur Verbesserung der Leistung von Entity Framework-Anwendungen verwenden können.

Phasen der Abfrageausführung

Zum besseren Verständnis der Abfrageleistung im Entity Framework ist es hilfreich zu verstehen, welche Vorgänge ablaufen, wenn eine Abfrage für ein konzeptionelles Modell ausgeführt wird und dabei Daten als Objekte zurückgegeben werden. Die folgende Tabelle beschreibt diese Reihe von Vorgängen.

Vorgang Relative Kosten Häufigkeit Kommentare

Laden von Metadaten

Mäßig

Einmal pro Anwendungsdomäne.

Von Entity Framework verwendete Modell- und Zuordnungsmetadaten werden in eine MetadataWorkspace geladen. Diese Metadaten werden global zwischengespeichert und stehen für weitere Instanzen von ObjectContext in der gleichen Anwendungsdomäne zur Verfügung.

Öffnen der Datenbankverbindung

Mäßig1

Nach Bedarf.

Da durch eine geöffnete Verbindung zur Datenbank wertvolle Ressourcen aufgebraucht werden, wird die Datenbankverbindung von Entity Framework nur bei Bedarf geöffnet bzw. geschlossen. Sie können die Verbindung auch explizit öffnen. Weitere Informationen erhalten Sie unter Verwalten von Verbindungen und Transaktionen (Entity Framework).

Generieren von Sichten

Hoch

Einmal pro Anwendungsdomäne. (Kann zuvor generiert werden.)

Bevor von Entity Framework für ein konzeptionelles Modell eine Abfrage ausgeführt oder Änderungen an der Datenquelle gespeichert werden können, muss ein Satz lokaler Abfrageansichten für den Zugriff auf die Datenbank generiert werden. Aufgrund der hohen Kosten für die Generierung dieser Sichten können Sie die Sichten zuvor generieren und dem Projekt zur Entwurfszeit hinzufügen. Weitere Informationen erhalten Sie unter Gewusst wie: Vorgenerieren von Sichten zur Verbesserung der Abfrageleistung.

Vorbereiten der Abfrage

Mäßig2

Einmal für jede eindeutige Abfrage.

Schließt die Kosten für das Verfassen des Abfragebefehls, die Erstellung einer Befehlsstruktur auf Grundlage von Modell- und Zuordnungsmetadaten und die Definition der Form der zurückgegebenen Daten ein. Da Entity SQL-Abfragebefehle zwischengespeichert werden, ist für spätere Ausführungen der gleichen Abfrage noch weniger Zeit erforderlich. Sie können kompilierte LINQ-Abfragen auch zur Reduzierung dieser Kosten in späteren Ausführungen verwenden. Weitere Informationen erhalten Sie unter Kompilierte Abfragen (LINQ to Entities). Allgemeine Informationen zu LINQ-Abfragen finden Sie unter LINQ to Entities.

Ausführen der Abfrage

Niedrig2

Einmal für jede Abfrage.

Die Kosten für das Ausführen des Befehls für die Datenquelle mithilfe des ADO.NET-Datenanbieters. Da von den meisten Datenquellen Abfragepläne zwischengespeichert werden, ist für spätere Ausführungen der gleichen Abfrage noch weniger Zeit erforderlich.

Laden und Überprüfen von Typen

Niedrig3

Einmal für jede ObjectContext-Instanz.

Typen werden geladen und für die Typen überprüft, die das konzeptionelle Modell definiert.

Nachverfolgung

Niedrig3

Einmal für jedes Objekt, das von einer Abfrage zurückgegeben wird. 4

Verwendet eine Abfrage die NoTracking-Zusammenführungsoption, wird die Leistung von dieser Phase nicht beeinträchtigt.

Verwendet die Abfrage die AppendOnly-, PreserveChanges- oder OverwriteChanges-Zusammenführungsoption, werden Abfrageergebnisse in der ObjectStateManager nachverfolgt. Für jedes von der Abfrage zurückgegebene verfolgte Objekt wird ein EntityKey generiert, das für die Erstellung eines ObjectStateManager im ObjectStateEntry verwendet wird. Wenn ein ObjectStateEntry für den EntityKey vorhanden ist, wird das vorhandene Objekt zurückgegeben. Wird die PreserveChanges- oder OverwriteChanges-Option verwendet, wird das Objekt vor der Rückgabe aktualisiert.

Weitere Informationen finden Sie unter Identitätsauflösung, Zustandsverwaltung und Änderungsnachverfolgung (Entity Framework).

Materialisieren der Objekte

Mäßig3

Einmal für jedes Objekt, das von einer Abfrage zurückgegeben wird. 4

Der Prozess des Lesens des zurückgegebenen DbDataReader-Objekts, des Erstellens von Objekten und des Festlegens von Eigenschaftswerten, die auf den Werten in jeder Instanz der DbDataRecord-Klasse basieren. Ist das Objekt bereits im ObjectContext vorhanden und werden von der Abfrage die AppendOnly- oder PreserveChanges-Zusammenführungsoptionen verwendet, wird von dieser Phase die Leistung nicht beeinträchtigt. Weitere Informationen finden Sie unter Identitätsauflösung, Zustandsverwaltung und Änderungsnachverfolgung (Entity Framework).

1 Implementiert ein Datenquellenanbieter Verbindungspooling, werden die Kosten für das Öffnen einer Verbindung im Pool verteilt. Der .NET-Anbieter für SQL Server unterstützt Verbindungspooling.

2Die Kosten nehmen mit höherer Abfragekomplexität zu.

3 Die Gesamtkosten steigen proportional zur Anzahl der von der Abfrage zurückgegebenen Objekte.

4 Dies ist für EntityClient-Abfragen nicht erforderlich, da von EntityClient statt der Objekte ein EntityDataReader zurückgegeben wird. Weitere Informationen finden Sie unter EntityClient-Anbieter für Entity Framework.

Weitere Überlegungen

Die im Folgenden beschriebenen Vorgehensweisen wirken sich möglicherweise auf die Leistung von Entity Framework-Anwendungen aus.

Abfrageausführung

Da Abfragen ressourcenintensiv sein können, muss berücksichtigt werden, an welcher Stelle im Code und auf welchem Computer eine Abfrage ausgeführt wird.

Verzögerte und unmittelbare Ausführung

Bei der Erstellung einer ObjectQuery- oder einer LINQ-Abfrage wird die Abfrage möglicherweise nicht sofort ausgeführt. Die Abfrageausführung wird so lange verzögert, bis die Ergebnisse benötigt werden, z. B. während einer foreach (C#)-Enumeration, einer For Each (Visual Basic)-Enumeration oder wenn eine List-Auflistung ausgefüllt werden soll. Die Abfrage wird ausgeführt, wenn Sie die Execute-Methode für ein ObjectQuery aufrufen oder wenn Sie eine LINQ-Methode aufrufen, die eine Singleton-Abfrage zurückgibt, z. B. First oder Any. Weitere Informationen finden Sie unter Objektabfragen (Entity Framework) und Query Execution (LINQ to Entities).

Clientseitige Ausführung von LINQ-Abfragen

Obwohl eine LINQ-Abfrage auf dem Computer ausgeführt wird, der die Datenquelle hostet, werden einige Teile der LINQ-Abfrage möglicherweise auf dem Clientcomputer ausgewertet. Weitere Informationen finden Sie im Abschnitt zur Speicherausführung unter Query Execution (LINQ to Entities).

Abfrage- und Zuordnungskomplexität

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

Zuordnungskomplexität

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

Abfragekomplexität

Abfragen, die eine große Anzahl von Joins für Befehle erfordern, die für die Datenquelle ausgeführt werden oder eine große Datenmenge zurückgeben, beeinträchtigen möglicherweise die Leistung auf die folgende Weise:

  • Scheinbar einfache Abfragen für ein konzeptionelles Modell führen möglicherweise zur Ausführung komplexerer Abfragen für die Datenquelle. Dies kann auftreten, da Entity Framework eine Abfrage für ein konzeptionelles Modell in eine entsprechende Abfrage für die Datenquelle übersetzt. Wenn ein einzelner Entitätssatz im konzeptionellen Modell mehr als einer Tabelle in der Datenquelle zugeordnet wird oder einer Jointabelle eine Beziehung zwischen Entitäten zugeordnet wird, sind für den Abfragebefehl für die Datenquellenabfrage möglicherweise Joins erforderlich.

    Cc853327.note(de-de,VS.100).gifHinweis:
    Verwenden Sie die ToTraceString-Methode der ObjectQuery- oder EntityCommand-Klasse, um die Befehle anzuzeigen, die für die Datenquelle für eine angegebene Abfrage ausgeführt werden.Weitere Informationen finden Sie unter Gewusst wie: Anzeigen der Speicherbefehle (Entity Framework).

  • Geschachtelte Entity SQL-Abfragen erstellen möglicherweise Joins auf dem Server und geben eine große Anzahl von Zeilen zurück.

    Im Folgenden 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 mit Verdoppelung von Objekten in geschachtelten Abfragen generiert. Deswegen wird eine einzelne Spalte möglicherweise mehrmals dupliziert. In einigen Datenbanken, einschließlich SQL Server, kann hierdurch die TempDB-Tabelle stark vergrößert werden und die Serverleistung abnehmen. Bei der Ausführung geschachtelter Abfragen sollte also vorsichtig vorgegangen werden.

  • Alle Abfragen, die eine große Datenmenge zurückgeben, können einen Leistungsabfall verursachen, wenn vom Client Vorgänge ausgeführt werden, von denen Ressourcen in der Größenordnung des Resultsets verbraucht werden. In solchen Fällen sollten Sie erwägen, die von der Abfrage zurückgegebene Datenmenge zu beschränken. Weitere Informationen finden Sie unter Gewusst wie: Seitenweise durch Abfrageresultate navigieren (Entity Framework).

Alle automatisch vom Entity Framework generierten Befehle sind möglicherweise komplexer als ähnliche explizit von einem Datenbankentwickler geschriebenen Befehle. Wenn Sie explizite Kontrolle über die für die Datenquelle ausgeführten Befehle benötigen, erwägen Sie die Definition einer Zuordnung für eine Tabellenwertfunktion oder eine gespeicherte Prozedur.

Beziehungen

Für optimale Abfrageleistung müssen Beziehungen zwischen Entitäten als Zuordnungen im Entitätsmodell und als logische Beziehungen in der Datenquelle definiert werden.

Abfragepfade

Standardmäßig werden verknüpfte Objekte nicht zurückgegeben (obwohl dies für Objekte, die die Beziehungen selbst darstellen, zutrifft), wenn Sie einen ObjectQuery ausführen. Sie können auf eine von drei Arten verknüpfte Objekte laden:

  1. Legen Sie den Abfragepfad fest, bevor die ObjectQuery-Abfrage ausgeführt wird.

  2. Rufen Sie die Load-Methode für die Navigationseigenschaft auf, die das Objekt verfügbar macht.

  3. Legen Sie die LazyLoadingEnabled-Option für das ObjectContext-Objekt auf true fest. Beachten Sie, dass dies automatisch geschieht, wenn Sie mit dem Entity Data Model Designer Code auf Objektebene generieren. Weitere Informationen finden Sie unter Generated Code Overview.

Denken Sie beim Auswählen der Option daran, dass zwischen der Anzahl der Abfragen der Datenbank und der in einer einzelnen Abfrage zurückgegebenen Datenmenge abgewogen werden sollte. Weitere Informationen finden Sie unter Laden von verknüpften Objekten (Entity Framework).

Verwenden von Abfragepfaden

Abfragepfade definieren das Diagramm von Objekten, die von einer Abfrage zurückgegeben werden. Beim Definieren eines Abfragepfads ist nur eine einzige Abfrage der Datenbank erforderlich, um alle durch den Pfad definierten Objekte zurückzugeben. Durch die Verwendung von Abfragepfaden können aus scheinbar einfachen Objektabfragen komplexe Befehle werden, die in der Datenquelle ausgeführt werden. Der Grund hierfür ist, dass eine oder mehrere Joins erforderlich sind, um verbundene Objekte in einer einzelnen Abfrage zurückzugeben. Diese Komplexität nimmt bei Abfragen für ein komplexes Entitätsmodell (z. B. eine Entität mit Vererbung oder ein Pfad, der n:n-Beziehungen enthält) zu.

Cc853327.note(de-de,VS.100).gifHinweis:
Mit der ToTraceString-Methode kann der von einer ObjectQuery generierte Befehl angezeigt werden.Weitere Informationen finden Sie unter Gewusst wie: Anzeigen der Speicherbefehle (Entity Framework).

Wenn ein Abfragepfad zu viele verbundene Objekte enthält oder die Objekte zu viele Zeilendaten enthalten, kann die Abfrage möglicherweise nicht von der Datenquelle abgeschlossen werden. Dies tritt auf, wenn die Abfrage temporäre Zwischenspeicherung erfordert, die die Kapazität der Datenquelle überschreitet. In diesem Fall kann die Komplexität der Datenquellenabfrage verringert werden, indem verbundene Objekte explizit geladen werden.

Explizites Laden verbundener Objekte

Zum expliziten Laden verwandter Objekte muss die Load-Methode für eine Navigationseigenschaft aufgerufen werden, die eine EntityCollection oder EntityReference zurückgibt. Explizites Laden erfordert bei jedem Aufruf von Load einen Roundtrip zur Datenbank.

Cc853327.note(de-de,VS.100).gifHinweis:
Wenn Sie beim Durchlaufen einer Auflistung zurückgegebener Objekte Load aufrufen, z. B. wenn Sie die foreach-Anweisung (For Each in Visual Basic) verwenden, muss der datenquellenspezifische Anbieter mehrere aktive Resultsets für eine einzelne Verbindung unterstützen.Bei einer SQL Server-Datenbank muss ein MultipleActiveResultSets = true-Wert in der Verbindungszeichenfolge des Anbieters angegeben werden.

Sie können auch die LoadProperty-Methode verwenden, wenn die Entitäten nicht über die EntityCollection-Eigenschaft oder die EntityReference-Eigenschaft verfügen. Dies ist bei Verwendung von POCO-Entitäten nützlich.

Obwohl durch das explizite Laden von verwandten Objekten die Anzahl der Joins und die Menge von redundanten Daten reduziert wird, erfordert Load wiederholte Verbindungen zur Datenbank, was beim expliziten Laden einer großen Anzahl von Objekten kostenintensiv sein kann.

Speichern von Änderungen

Wenn Sie die SaveChanges-Methode für einen ObjectContext aufrufen, wird für jedes hinzugefügte, aktualisierte oder gelöschte Objekt im Kontext jeweils ein eigener Befehl zum Erstellen, Aktualisieren oder Löschen generiert. Diese Befehle werden für die Datenquelle in einer einzelnen Transaktion ausgeführt. Wie bei Abfragen ist die Leistung von Vorgängen für die Erstellung, Aktualisierung und Löschung von der Komplexität der Zuordnung im konzeptionellen Modell abhängig.

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 DTC nicht erfordert. In den folgenden Situationen findet eine Höherstufung zum DTC statt:

  • 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 für SQL Server 2005, wenn die Verbindung von Entity Framework verwaltet wird. Dies tritt auf, da SQL Server 2005 immer dann auf einen DTC hochstuft, wenn eine Verbindung geschlossen und innerhalb einer einzelnen Transaktion erneut geöffnet wird. Dies ist das Standardverhalten von Entity Framework . Bei SQL Server 2008 wird diese DTC-Höherstufung nicht durchgeführt. Öffnen und schließen Sie explizit die Verbindung innerhalb der Transaktion, um diese Höherstufung zu vermeiden, wenn Sie SQL Server 2005 verwenden. Weitere Informationen erhalten Sie unter Verwalten von Verbindungen und Transaktionen (Entity Framework).

Eine explizite Transaktion wird verwendet, wenn ein oder mehrere Vorgänge in einer System.Transactions-Transaktion ausgeführt werden. Weitere Informationen erhalten Sie unter Verwalten von Verbindungen und Transaktionen (Entity Framework).

Strategien zum Verbessern der Leistung

Sie können die Gesamtleistung von Abfragen in Entity Framework mit den folgenden Strategien verbessern.

Vorabgenerieren von Sichten

Führt eine Anwendung eine Abfrage zum ersten Mal aus, ist das Generieren von Sichten auf Grundlage eines Entitätsmodells kostenintensiv. Verwenden Sie das Hilfsprogramm "EdmGen.exe", um Ansichten als eine Visual Basic- oder eine C#-Codedatei vorzugenerieren, die dem Projekt während des Entwurfs hinzugefügt werden kann. Zur Wahrung der Konsistenz mit der aktuellen Version des angegebenen Entitätsmodells werden vorgenerierte Ansichten zur Laufzeit überprüft. Weitere Informationen finden Sie unter Gewusst wie: Vorgenerieren von Sichten zur Verbesserung der Abfrageleistung.

Verwenden der NoTracking-Zusammenführungsoption für Abfragen

Das Nachverfolgen von zurückgegebenen Objekten im Objektkontext bringt Kosten mit sich. Zur Ermittlung von Änderungen an Objekten und zur Gewährleistung, dass mehrere Anforderungen für die gleiche logische Entität die gleiche Objektinstanz zurückgeben, ist das Anfügen der Objekte an die ObjectContext-Instanz erforderlich. Wenn Sie nicht vorhaben, Objekte zu aktualisieren oder zu löschen und keine Identitätsverwaltung benötigen, sollten Sie beim Ausführen von Abfragen die Verwendung von NoTracking-Zusammenführungsoptionen in Betracht ziehen.

Verwenden kompilierter LINQ-Abfragen

Wenn eine Anwendung im Entity Framework häufig strukturell ähnliche Abfragen ausführt, kann in vielen Fällen die Leistung gesteigert werden, indem die Abfrage einmal kompiliert und anschließend mehrmals mit verschiedenen Parametern ausgeführt wird. So können beispielsweise mithilfe einer Anwendung alle Kunden in einer bestimmten Stadt abgerufen werden, wobei die Stadt zur Laufzeit vom Benutzer in einem Formular festgelegt wird. Für derartige Aufgaben unterstützt LINQ to Entities die Verwendung kompilierter Abfragen. Die Abfrage wird nur einmal während der ersten Ausführung kompiliert. Die für die Abfrage zur Kompilierungszeit festgelegten Zusammenführungsoptionen können später nicht geändert werden.

Weitere Informationen finden Sie unter Kompilierte Abfragen (LINQ to Entities).

Zurückgeben der richtigen Datenmenge

In einigen Szenarien ist das Angeben eines Abfragepfads mithilfe der Include-Methode viel schneller, da weniger Roundtrips zur Datenbank erforderlich sind. Allerdings sind in anderen Szenarien zusätzliche Roundtrips zur Datenbank zum Laden von verknüpften Objekten ggf. schneller, da die einfacheren Abfragen mit weniger Joins weniger redundante Daten liefern. Deswegen empfiehlt es sich, verschiedene Möglichkeiten zum Abrufen verknüpfter Objekte zu testen und so die leistungsfähigste Methode zu ermitteln. Weitere Informationen finden Sie unter Laden von verknüpften Objekten (Entity Framework).

Gliedern Sie die Abfrageergebnisse in überschaubare Gruppen, um zu vermeiden, dass zu viel Daten in einer einzelnen Abfrage zurückgegeben werden. Weitere Informationen finden Sie unter Gewusst wie: Seitenweise durch Abfrageresultate navigieren (Entity Framework).

Einschränken des Bereichs des ObjectContext

In den meisten Fällen sollten Sie eine ObjectContext-Instanz innerhalb einer using-Anweisung (Using…End Using in Visual Basic) erstellen. Dies kann die Leistung verbessern, da die dem Objektkontext zugeordneten Ressourcen automatisch freigegeben werden, wenn der Anweisungsblock vom Code beendet wird. Wenn Steuerelemente jedoch an vom Objektkontext verwaltete Objekte gebunden werden, sollte die ObjectContext-Instanz so lange beibehalten werden, wie die Bindung benötigt wird, und manuell freigegeben werden. Weitere Informationen finden Sie unter Verwalten von Verbindungen und Transaktionen (Entity Framework).

Manuelles Öffnen der Datenbankverbindung

Wenn die Anwendung eine Reihe von Objektabfragen ausführt oder häufig SaveChanges aufruft, um Vorgänge für das Erstellen, Aktualisieren und Löschen in der Datenquelle zu speichern, muss von Entity Framework die Verbindung zur Datenquelle ständig öffnen und schließen. Erwägen Sie in diesem Fall, die Verbindung am Start dieser Vorgänge manuell zu öffnen und die Verbindung zu schließen bzw. freizugeben, wenn die Vorgänge abgeschlossen sind. Weitere Informationen finden Sie unter Verwalten von Verbindungen und Transaktionen (Entity Framework).

Leistungsdaten

Einige Leistungsdaten für Entity Framework wurden auf dem ADO.NET-Teamblog in den folgenden Beiträgen veröffentlicht (ggf. nur in englischer Sprache verfügbar):

Siehe auch

Konzepte

Überlegungen zur Entwicklung und Bereitstellung (Entity Framework)