Prestatieoverwegingen (Entity Framework)
In dit onderwerp worden prestatiekenmerken van het ADO.NET Entity Framework beschreven en worden enkele overwegingen gegeven om de prestaties van Entity Framework-toepassingen te verbeteren.
Fasen van het uitvoeren van query's
Om de prestaties van query's in Entity Framework beter te begrijpen, is het handig om inzicht te krijgen in de bewerkingen die optreden wanneer een query wordt uitgevoerd op basis van een conceptueel model en gegevens als objecten retourneert. In de volgende tabel wordt deze reeks bewerkingen beschreven.
Operation | Relatieve kosten | Frequentie | Opmerkingen |
---|---|---|---|
Metagegevens laden | Matig | Eenmaal in elk toepassingsdomein. | Model- en toewijzingsmetagegevens die door het Entity Framework worden gebruikt, worden geladen in een MetadataWorkspace. Deze metagegevens worden globaal in de cache opgeslagen en zijn beschikbaar voor andere exemplaren in ObjectContext hetzelfde toepassingsdomein. |
De databaseverbinding openen | Gemiddeld1 | Indien nodig. | Omdat een geopende verbinding met de database een waardevolle resource verbruikt, wordt entity framework geopend en wordt de databaseverbinding alleen gesloten als dat nodig is. U kunt de verbinding ook expliciet openen. Zie Verbinding maken ions en transacties beheren voor meer informatie. |
Weergaven genereren | Hoog | Eenmaal in elk toepassingsdomein. (Kan vooraf worden gegenereerd.) | Voordat Entity Framework een query kan uitvoeren op basis van een conceptueel model of wijzigingen in de gegevensbron kan opslaan, moet deze een set lokale queryweergaven genereren voor toegang tot de database. Vanwege de hoge kosten voor het genereren van deze weergaven, kunt u de weergaven vooraf genereren en toevoegen aan het project tijdens het ontwerpen. Zie Procedure voor meer informatie : Weergaven vooraf genereren om de queryprestaties te verbeteren. |
De query voorbereiden | Gemiddeld2 | Eenmaal voor elke unieke query. | Omvat de kosten voor het opstellen van de queryopdracht, het genereren van een opdrachtstructuur op basis van model en toewijzingsmetagegevens en het definiëren van de vorm van de geretourneerde gegevens. Omdat nu zowel Entiteit SQL-queryopdrachten als LINQ-query's in de cache worden opgeslagen, duurt het later minder tijd om dezelfde query uit te voeren. U kunt gecompileerde LINQ-query's nog steeds gebruiken om deze kosten in latere uitvoeringen te verlagen en gecompileerde query's kunnen efficiënter zijn dan LINQ-query's die automatisch in de cache worden opgeslagen. Zie Gecompileerde query's (LINQ naar entiteiten) voor meer informatie. Zie LINQ naar entiteiten voor algemene informatie over het uitvoeren van LINQ-query's. Opmerking: LINQ op entiteitenquery's die de operator toepassen op in-memory verzamelingen, worden niet automatisch in de Enumerable.Contains cache opgeslagen. Het parameteriseren van in-memory verzamelingen in gecompileerde LINQ-query's is ook niet toegestaan. |
De query uitvoeren | Laag2 | Eenmaal voor elke query. | De kosten voor het uitvoeren van de opdracht voor de gegevensbron met behulp van de ADO.NET gegevensprovider. Omdat de meeste gegevensbronnen queryplannen in de cache opslaan, kan het later uitvoeren van dezelfde query nog minder tijd in beslag nemen. |
Typen laden en valideren | Laag3 | Eenmaal voor elk ObjectContext exemplaar. | Typen worden geladen en gevalideerd op basis van de typen die door het conceptuele model worden gedefinieerd. |
Bijhouden | Laag3 | Eenmaal voor elk object dat door een query wordt geretourneerd. 4 | Als een query gebruikmaakt van de NoTracking samenvoegoptie, heeft deze fase geen invloed op de prestaties. Als de query gebruikmaakt van de AppendOnlyoptie , PreserveChangesof OverwriteChanges samenvoegen, worden queryresultaten bijgehouden in de ObjectStateManager. Er EntityKey wordt een gegenereerd voor elk bijgehouden object dat door de query wordt geretourneerd en wordt gebruikt om een ObjectStateEntry in de ObjectStateManagerquery te maken. Als er een bestaande ObjectStateEntry kan worden gevonden voor de EntityKey, wordt het bestaande object geretourneerd. Als de PreserveChangesoptie of OverwriteChanges de optie wordt gebruikt, wordt het object bijgewerkt voordat het wordt geretourneerd. Zie Identity Resolution, State Management en Wijzigingen bijhouden voor meer informatie. |
De objecten materialiseren | Gemiddeld3 | Eenmaal voor elk object dat door een query wordt geretourneerd. 4 | Het proces van het lezen van het geretourneerde DbDataReader object en het maken van objecten en het instellen van eigenschapswaarden die zijn gebaseerd op de waarden in elk exemplaar van de DbDataRecord klasse. Als het object al bestaat in de ObjectContext query en de query de AppendOnly opties voor samenvoegen PreserveChanges gebruikt, heeft deze fase geen invloed op de prestaties. Zie Identity Resolution, State Management en Wijzigingen bijhouden voor meer informatie. |
1 Wanneer een gegevensbronprovider groepsgewijze verbindingen implementeert, worden de kosten voor het openen van een verbinding verdeeld over de pool. De .NET-provider voor SQL Server ondersteunt groepsgewijze verbindingen.
2 Kosten nemen toe met een hogere querycomplexiteit.
3 Totale kosten stijgen evenredig met het aantal objecten dat door de query wordt geretourneerd.
4 Deze overhead is niet vereist voor EntityClient-query's omdat EntityClient-query's een EntityDataReader in plaats van objecten retourneren. Zie EntityClient-provider voor het Entity Framework voor meer informatie.
Aanvullende overwegingen
Hier volgen andere overwegingen die van invloed kunnen zijn op de prestaties van Entity Framework-toepassingen.
Queryuitvoering
Omdat query's resource-intensief kunnen zijn, kunt u overwegen op welk punt in uw code en op welke computer een query wordt uitgevoerd.
Uitgestelde versus onmiddellijke uitvoering
Wanneer u een ObjectQuery<T> of LINQ-query maakt, wordt de query mogelijk niet onmiddellijk uitgevoerd. De uitvoering van query's wordt uitgesteld totdat de resultaten nodig zijn, zoals tijdens een foreach
opsomming (C#) of For Each
(Visual Basic) of wanneer deze is toegewezen om een List<T> verzameling te vullen. De uitvoering van query's begint onmiddellijk wanneer u de Execute methode aanroept op een ObjectQuery<T> of wanneer u een LINQ-methode aanroept die een singleton-query retourneert, zoals First of Any. Zie Objectquery's en Query-uitvoering (LINQ naar entiteiten) voor meer informatie.
Uitvoering van LINQ-query's aan de clientzijde
Hoewel de uitvoering van een LINQ-query plaatsvindt op de computer waarop de gegevensbron wordt gehost, kunnen sommige onderdelen van een LINQ-query worden geëvalueerd op de clientcomputer. Zie de sectie Store Execution van Query Execution (LINQ to Entities) voor meer informatie.
Complexiteit van query's en toewijzingen
De complexiteit van afzonderlijke query's en de toewijzing in het entiteitsmodel heeft een aanzienlijk effect op de queryprestaties.
Toewijzingscomplexiteit
Modellen die complexer zijn dan een eenvoudige een-op-een-toewijzing tussen entiteiten in het conceptuele model en tabellen in het opslagmodel genereren complexere opdrachten dan modellen met een een-op-een-toewijzing.
Querycomplexiteit
Query's waarvoor een groot aantal joins is vereist in de opdrachten die worden uitgevoerd op de gegevensbron of die een grote hoeveelheid gegevens retourneren, kunnen de prestaties op de volgende manieren beïnvloeden:
Query's op basis van een conceptueel model dat eenvoudig lijkt, kunnen leiden tot de uitvoering van complexere query's voor de gegevensbron. Dit kan gebeuren omdat entity framework een query vertaalt op basis van een conceptueel model in een equivalente query voor de gegevensbron. Wanneer één entiteit die in het conceptuele model is ingesteld, wordt toegewezen aan meer dan één tabel in de gegevensbron of wanneer een relatie tussen entiteiten is toegewezen aan een jointabel, kan de queryopdracht die wordt uitgevoerd op basis van de gegevensbronquery een of meer joins vereisen.
Notitie
Gebruik de ToTraceString methode van de ObjectQuery<T> of EntityCommand klassen om de opdrachten weer te geven die worden uitgevoerd op de gegevensbron voor een bepaalde query. Zie Instructies voor meer informatie : De Store-opdrachten weergeven.
Geneste Entiteit SQL-query's kunnen joins maken op de server en kunnen een groot aantal rijen retourneren.
Hier volgt een voorbeeld van een geneste query in een projectiecomponent:
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
Bovendien zorgen dergelijke query's ervoor dat de querypijplijn één query genereert met duplicatie van objecten in geneste query's. Hierdoor kan één kolom meerdere keren worden gedupliceerd. Op sommige databases, waaronder SQL Server, kan dit ertoe leiden dat de TempDB-tabel zeer groot wordt, waardoor de serverprestaties kunnen afnemen. Zorg ervoor dat u geneste query's uitvoert.
Query's die een grote hoeveelheid gegevens retourneren, kunnen verminderde prestaties veroorzaken als de client bewerkingen uitvoert die resources verbruiken op een manier die evenredig is met de grootte van de resultatenset. In dergelijke gevallen moet u overwegen de hoeveelheid gegevens te beperken die door de query worden geretourneerd. Zie Procedure voor meer informatie : Page Through Query Results.
Opdrachten die automatisch door entity Framework worden gegenereerd, kunnen complexer zijn dan vergelijkbare opdrachten die expliciet zijn geschreven door een databaseontwikkelaar. Als u expliciet controle nodig hebt over de opdrachten die worden uitgevoerd voor uw gegevensbron, kunt u overwegen een toewijzing te definiëren aan een functie met tabelwaarde of opgeslagen procedure.
Relaties
Voor optimale queryprestaties moet u relaties tussen entiteiten definiëren als koppelingen in het entiteitsmodel en als logische relaties in de gegevensbron.
Querypaden
Wanneer u een ObjectQuery<T>gerelateerde objecten uitvoert, worden standaard niet geretourneerd (hoewel objecten die de relaties zelf vertegenwoordigen). U kunt gerelateerde objecten op drie manieren laden:
Stel het querypad in voordat het ObjectQuery<T> wordt uitgevoerd.
Roep de
Load
methode aan op de navigatie-eigenschap die door het object wordt weergegeven.Stel de LazyLoadingEnabled optie in op ObjectContext
true
. Houd er rekening mee dat dit automatisch wordt gedaan wanneer u code op objectlaag genereert met entity data model designer. Zie Overzicht van gegenereerde code voor meer informatie.
Wanneer u bedenkt welke optie u wilt gebruiken, moet u er rekening mee houden dat er een afweging is tussen het aantal aanvragen voor de database en de hoeveelheid gegevens die in één query wordt geretourneerd. Zie Gerelateerde objecten laden voor meer informatie.
Querypaden gebruiken
Querypaden definiëren de grafiek van objecten die een query retourneert. Wanneer u een querypad definieert, is slechts één aanvraag voor de database vereist om alle objecten te retourneren die door het pad worden gedefinieerd. Als u querypaden gebruikt, kunnen complexe opdrachten worden uitgevoerd op basis van de gegevensbron vanuit schijnbaar eenvoudige objectquery's. Dit komt doordat een of meer joins vereist zijn om gerelateerde objecten in één query te retourneren. Deze complexiteit is groter in query's voor een complex entiteitsmodel, zoals een entiteit met overname of een pad met veel-op-veel-relaties.
Notitie
Gebruik de methode om de ToTraceString opdracht te zien die wordt gegenereerd door een ObjectQuery<T>. Zie Instructies voor meer informatie : De Store-opdrachten weergeven.
Wanneer een querypad te veel gerelateerde objecten bevat of de objecten te veel rijgegevens bevatten, kan de gegevensbron de query mogelijk niet voltooien. Dit gebeurt als de query tussenliggende tijdelijke opslag vereist die de mogelijkheden van de gegevensbron overschrijdt. Wanneer dit gebeurt, kunt u de complexiteit van de gegevensbronquery verminderen door gerelateerde objecten expliciet te laden.
Gerelateerde objecten expliciet laden
U kunt gerelateerde objecten expliciet laden door de Load
methode aan te roepen op een navigatie-eigenschap die een EntityCollection<TEntity> of EntityReference<TEntity>retourneert. Het expliciet laden van objecten vereist een retour naar de database telkens wanneer Load
deze wordt aangeroepen.
Notitie
als u Load
belt tijdens het doorlopen van een verzameling geretourneerde objecten, zoals wanneer u de foreach
instructie (For Each
in Visual Basic) gebruikt, moet de gegevensbronspecifieke provider meerdere actieve resultatensets op één verbinding ondersteunen. Voor een SQL Server-database moet u een waarde opgeven van MultipleActiveResultSets = true
de provider verbindingsreeks.
U kunt de LoadProperty methode ook gebruiken wanneer er geen EntityCollection<TEntity> of EntityReference<TEntity> eigenschappen zijn voor entiteiten. Dit is handig wanneer u POCO-entiteiten gebruikt.
Hoewel het expliciet laden van gerelateerde objecten het aantal joins vermindert en de hoeveelheid redundante gegevens vermindert, Load
zijn herhaalde verbindingen met de database vereist, wat kostbaar kan worden bij het expliciet laden van een groot aantal objecten.
Wijzigingen opslaan
Wanneer u de SaveChanges methode op een ObjectContextaanroept, wordt er een afzonderlijke opdracht voor maken, bijwerken of verwijderen gegenereerd voor elk toegevoegd, bijgewerkt of verwijderd object in de context. Deze opdrachten worden uitgevoerd op de gegevensbron in één transactie. Net als bij query's zijn de prestaties van bewerkingen voor maken, bijwerken en verwijderen afhankelijk van de complexiteit van de toewijzing in het conceptuele model.
Gedistribueerde transacties
Bewerkingen in een expliciete transactie die resources vereisen die worden beheerd door de DTC (Gedistribueerde transactiecoördinator) zijn veel duurder dan een vergelijkbare bewerking waarvoor de DTC niet nodig is. Promotie naar de DTC vindt plaats in de volgende situaties:
Een expliciete transactie met een bewerking op basis van een SQL Server 2000-database of andere gegevensbron die altijd expliciete transacties naar de DTC promoveren.
Een expliciete transactie met een bewerking met SQL Server 2005 wanneer de verbinding wordt beheerd door entity framework. Dit komt doordat SQL Server 2005 promoveert naar een DTC wanneer een verbinding wordt gesloten en opnieuw wordt geopend binnen één transactie, wat het standaardgedrag van het Entity Framework is. Deze DTC-promotie vindt niet plaats wanneer u SQL Server 2008 gebruikt. Om deze promotie te voorkomen bij het gebruik van SQL Server 2005, moet u de verbinding binnen de transactie expliciet openen en sluiten. Zie Verbinding maken ions en transacties beheren voor meer informatie.
Een expliciete transactie wordt gebruikt wanneer een of meer bewerkingen worden uitgevoerd binnen een System.Transactions transactie. Zie Verbinding maken ions en transacties beheren voor meer informatie.
Strategieën voor het verbeteren van de prestaties
U kunt de algehele prestaties van query's in Entity Framework verbeteren met behulp van de volgende strategieën.
Vooraf gegenereerde weergaven
Het genereren van weergaven op basis van een entiteitsmodel is een aanzienlijke kosten de eerste keer dat een toepassing een query uitvoert. Gebruik het hulpprogramma EdmGen.exe om vooraf weergaven te genereren als een Visual Basic- of C#-codebestand dat tijdens het ontwerp aan het project kan worden toegevoegd. U kunt ook de Text Template Transformation Toolkit gebruiken om vooraf gecompileerde weergaven te genereren. Vooraf gegenereerde weergaven worden tijdens runtime gevalideerd om ervoor te zorgen dat ze consistent zijn met de huidige versie van het opgegeven entiteitsmodel. Zie Procedure voor meer informatie : Weergaven vooraf genereren om de queryprestaties te verbeteren.
Bij het werken met zeer grote modellen is de volgende overweging van toepassing:
De indeling voor metagegevens van .NET beperkt het aantal tekenreekstekens in een bepaalde binaire waarde tot 16.777.215 (0xFFFFFF). Als u weergaven voor een zeer groot model genereert en het weergavebestand deze groottelimiet bereikt, krijgt u de fout 'Geen logische ruimte meer gebruikerstekenreeksen maken'. Deze groottebeperking is van toepassing op alle beheerde binaire bestanden. Zie de blog die laat zien hoe u de fout kunt voorkomen bij het werken met grote en complexe modellen.
Overweeg het gebruik van de optie Voor het samenvoegen van NoTracking voor query's
Er zijn kosten vereist voor het bijhouden van geretourneerde objecten in de objectcontext. Als u wijzigingen in objecten detecteert en ervoor zorgt dat meerdere aanvragen voor dezelfde logische entiteit hetzelfde objectexemplaar retourneren, moeten objecten aan een ObjectContext exemplaar worden gekoppeld. Als u niet van plan bent om wijzigingen aan of verwijderingen aan objecten aan te brengen en geen identiteitsbeheer nodig hebt, kunt u overwegen om de NoTracking samenvoegopties te gebruiken wanneer u query's uitvoert.
De juiste hoeveelheid gegevens retourneren
In sommige scenario's is het opgeven van een querypad met behulp van de Include methode veel sneller omdat er minder retouren naar de database nodig zijn. In andere scenario's kunnen extra retouren naar de database om gerelateerde objecten te laden echter sneller zijn omdat de eenvoudigere query's met minder joins leiden tot minder redundantie van gegevens. Daarom raden we u aan om de prestaties van verschillende manieren te testen om gerelateerde objecten op te halen. Zie Gerelateerde objecten laden voor meer informatie.
Als u wilt voorkomen dat er te veel gegevens in één query worden geretourneerd, kunt u de resultaten van de query in beter beheerbare groepen paglen. Zie Procedure voor meer informatie : Page Through Query Results.
Het bereik van objectcontext beperken
In de meeste gevallen moet u een ObjectContext exemplaar binnen een using
instructieUsing…End Using
(in Visual Basic) maken. Dit kan de prestaties verbeteren door ervoor te zorgen dat de resources die aan de objectcontext zijn gekoppeld, automatisch worden verwijderd wanneer de code het instructieblok verlaat. Wanneer besturingselementen echter zijn gebonden aan objecten die worden beheerd door de objectcontext, moet het ObjectContext exemplaar worden onderhouden zolang de binding nodig is en handmatig wordt verwijderd. Zie Verbinding maken ions en transacties beheren voor meer informatie.
Overweeg om de databaseverbinding handmatig te openen
Wanneer uw toepassing een reeks objectquery's uitvoert of vaak aanroept SaveChanges om bewerkingen voor het maken, bijwerken en verwijderen van bewerkingen naar de gegevensbron vast te leggen, moet het Entity Framework continu de verbinding met de gegevensbron openen en sluiten. In deze situaties kunt u overwegen de verbinding handmatig te openen aan het begin van deze bewerkingen en de verbinding te sluiten of te verwijderen wanneer de bewerkingen zijn voltooid. Zie Verbinding maken ions en transacties beheren voor meer informatie.
Prestatiegegevens
Sommige prestatiegegevens voor Entity Framework worden gepubliceerd in de volgende berichten op de blog van het ADO.NET team:
De prestaties van het ADO.NET Entity Framework verkennen - deel 1
De prestaties van het ADO.NET Entity Framework – deel 2 verkennen