Sdílet prostřednictvím


Důležité informace o výkonu (Entity Framework)

Toto téma popisuje charakteristiky výkonu ADO.NET Entity Framework a poskytuje některé aspekty, které pomáhají zlepšit výkon aplikací Entity Framework.

Fáze provádění dotazů

Aby bylo možné lépe porozumět výkonu dotazů v Entity Frameworku, je užitečné pochopit operace, ke kterým dochází při provádění dotazu s koncepčním modelem, a vrátit data jako objekty. Následující tabulka popisuje tuto řadu operací.

Operace Relativní náklady Četnost Komentáře
Načítání metadat Pokročilé Jednou v každé doméně aplikace. Do objektu Entity Framework se načtou metadata modelu a mapování používaná rozhraním MetadataWorkspaceEntity Framework . Tato metadata se ukládají globálně do mezipaměti a jsou k dispozici pro jiné instance ObjectContext ve stejné doméně aplikace.
Otevření připojení k databázi Střední1 Podle potřeby. Vzhledem k tomu, že otevřené připojení k databázi využívá cenný prostředek, otevře se Entity Framework a podle potřeby zavře připojení k databázi. Připojení můžete také explicitně otevřít. Další informace naleznete v tématu Správa Připojení ionů a transakcí.
Generování zobrazení Vysoká Jednou v každé doméně aplikace. (Dá se předem vygenerovat.) Než entity Framework může spustit dotaz na koncepční model nebo uložit změny ve zdroji dat, musí vygenerovat sadu zobrazení místních dotazů pro přístup k databázi. Vzhledem k vysokým nákladům na generování těchto zobrazení můžete předem vygenerovat zobrazení a přidat je do projektu v době návrhu. Další informace naleznete v tématu Postupy: Předgenerování zobrazení za účelem zlepšení výkonu dotazů.
Příprava dotazu Střední2 Jednou pro každý jedinečný dotaz. Zahrnuje náklady na vytvoření příkazu dotazu, vygenerování stromu příkazů na základě metadat modelu a mapování a definování tvaru vrácených dat. Vzhledem k tomu, že příkazy dotazu Entity SQL i dotazy LINQ se ukládají do mezipaměti, pozdější spuštění stejného dotazu trvají méně času. Kompilované dotazy LINQ můžete stále použít ke snížení těchto nákladů v pozdějších spuštěních a kompilovaných dotazů může být efektivnější než dotazy LINQ, které se automaticky ukládají do mezipaměti. Další informace najdete v tématu Kompilované dotazy (LINQ to Entities). Obecné informace o provádění dotazů LINQ naleznete v tématu LINQ to Entities. Poznámka: Dotazy LINQ to Entities, které operátor aplikují Enumerable.Contains na kolekce v paměti, se automaticky neukládají do mezipaměti. Parametrizace kolekcí v paměti v kompilovaných dotazech LINQ není povolena.
Spuštění dotazu Nízká2 Jednou pro každý dotaz. Náklady na provedení příkazu vůči zdroji dat pomocí poskytovatele dat ADO.NET. Vzhledem k tomu, že většina zdrojů dat ukládá plány dotazů do mezipaměti, může pozdější spuštění stejného dotazu trvat ještě méně času.
Načítání a ověřování typů Nízká3 Jednou pro každou ObjectContext instanci. Typy se načítají a ověřují proti typům, které definuje koncepční model.
Sledování Nízká3 Jednou pro každý objekt, který dotaz vrátí. 4 Pokud dotaz používá NoTracking možnost sloučení, tato fáze nemá vliv na výkon.

Pokud dotaz používá AppendOnlymožnost , PreserveChangesnebo OverwriteChanges sloučení, výsledky dotazu jsou sledovány v sadě ObjectStateManager. Pro EntityKey každý sledovaný objekt, který dotaz vrátí, a slouží k vytvoření v ObjectStateEntry objektu ObjectStateManager. Pokud lze pro objekt EntityKeynajít existující ObjectStateEntry objekt, vrátí se existující objekt. PreserveChangesPokud se použije možnost nebo OverwriteChanges , objekt se před vrácením aktualizuje.

Další informace najdete v tématu Řešení identit, správa stavu a sledování změn.
Materializace objektů Střední3 Jednou pro každý objekt, který dotaz vrátí. 4 Proces čtení vráceného DbDataReader objektu a vytváření objektů a nastavení hodnot vlastností, které jsou založeny na hodnotách v každé instanci DbDataRecord třídy. Pokud objekt již v objektu ObjectContext existuje a dotaz používá AppendOnly možnosti sloučení, PreserveChanges tato fáze nemá vliv na výkon. Další informace najdete v tématu Řešení identit, správa stavu a sledování změn.

1 Když poskytovatel zdroje dat implementuje sdružování připojení, náklady na otevření připojení se distribuují napříč fondem. Zprostředkovatel .NET pro SQL Server podporuje sdružování připojení.

2 Zvýšení nákladů se zvýšenou složitostí dotazů

3 Celkové náklady se zvyšují úměrně počtu objektů vrácených dotazem.

4 Tato režie není nutná pro dotazy EntityClient, protože dotazy EntityClient vrací místo EntityDataReader objektů. Další informace naleznete v tématu EntityClient Provider for the Entity Framework.

Další důležité informace

Dále jsou uvedené další aspekty, které mohou ovlivnit výkon aplikací Entity Framework.

Provádění dotazů

Vzhledem k tomu, že dotazy můžou být náročné na prostředky, zvažte v jakém okamžiku v kódu a v jakém počítači se dotaz spouští.

Odložené a okamžité spuštění

Při vytváření ObjectQuery<T> dotazu nebo LINQ se dotaz nemusí spustit okamžitě. Provádění dotazu je odloženo, dokud nebudou potřeba výsledky, například během foreach výčtu (C#) nebo For Each (Visual Basic) nebo při přiřazení k vyplnění List<T> kolekce. Provádění dotazu začíná okamžitě, když voláte metodu ObjectQuery<T> nebo když voláte Execute metodu LINQ, která vrací jednoúčelový dotaz, například First nebo Any. Další informace najdete v tématu Dotazy na objekty a spouštění dotazů (LINQ to Entities).

Spouštění dotazů LINQ na straně klienta

Přestože provádění dotazu LINQ probíhá v počítači, který je hostitelem zdroje dat, některé části dotazu LINQ mohou být vyhodnoceny v klientském počítači. Další informace najdete v části Spouštění dotazů úložiště (LINQ to Entities).

Složitost dotazů a mapování

Složitost jednotlivých dotazů a mapování v modelu entit bude mít významný vliv na výkon dotazů.

Složitost mapování

Modely, které jsou složitější než jednoduché mapování 1:1 mezi entitami v konceptuálním modelu a tabulkami v modelu úložiště, generují složitější příkazy než modely, které mají mapování 1:1.

Složitost dotazů

Dotazy, které vyžadují velký počet spojení v příkazech spouštěných proti zdroji dat nebo které vrací velké množství dat, můžou ovlivnit výkon následujícími způsoby:

  • Dotazy na konceptuální model, který se zdá být jednoduchý, můžou vést k provádění složitějších dotazů ve zdroji dat. K tomu může dojít, protože Entity Framework překládá dotaz na konceptuální model na ekvivalentní dotaz vůči zdroji dat. Pokud se jedna sada entit v koncepčním modelu mapuje na více než jednu tabulku ve zdroji dat nebo když je relace mezi entitami namapovaná na tabulku spojení, může příkaz dotazu spuštěný s dotazem zdroje dat vyžadovat jedno nebo více spojení.

    Poznámka:

    ToTraceString Použijte metodu ObjectQuery<T> nebo EntityCommand třídy k zobrazení příkazů, které jsou spuštěny ve zdroji dat pro daný dotaz. Další informace naleznete v tématu Postupy: Zobrazení příkazů úložiště.

  • Vnořené dotazy Entity SQL můžou na serveru vytvářet spojení a můžou vracet velký počet řádků.

    Následuje příklad vnořeného dotazu v klauzuli projekce:

    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  
    

    Kromě toho tyto dotazy způsobí, že kanál dotazu vygeneruje jeden dotaz s duplikací objektů napříč vnořenými dotazy. Z tohoto důvodu může být jeden sloupec duplikován vícekrát. U některých databází, včetně SQL Serveru, to může způsobit, že tabulka TempDB bude velmi velká, což může snížit výkon serveru. Při spouštění vnořených dotazů je potřeba věnovat pozornost.

  • Všechny dotazy, které vracejí velké množství dat, můžou způsobit snížení výkonu, pokud klient provádí operace, které spotřebovávají prostředky způsobem, který je úměrný velikosti sady výsledků. V takových případech byste měli zvážit omezení množství dat vrácených dotazem. Další informace naleznete v tématu Postupy: Page Through Query Results.

Všechny příkazy automaticky generované rozhraním Entity Framework mohou být složitější než podobné příkazy napsané explicitně vývojářem databáze. Pokud potřebujete explicitní kontrolu nad příkazy spouštěné ve zdroji dat, zvažte definování mapování na funkci s hodnotou tabulky nebo uloženou proceduru.

Relace

Pokud chcete dosáhnout optimálního výkonu dotazů, musíte definovat relace mezi entitami jak jako přidružení v modelu entit, tak jako logické relace ve zdroji dat.

Cesty dotazů

Ve výchozím nastavení se při spuštění ObjectQuery<T>související objekty nevrátí (i když objekty, které představují samotné relace). Související objekty můžete načíst jedním ze tří způsobů:

  1. Nastavte cestu dotazu před spuštěním ObjectQuery<T> .

  2. Volejte metodu Load na navigační vlastnosti, kterou objekt zveřejňuje.

  3. LazyLoadingEnabled Nastavte možnost na ObjectContext hodnotu true. Všimněte si, že se to provádí automaticky při generování kódu vrstvy objektu pomocí Návrháře modelu Entity Data Model. Další informace naleznete v tématu Přehled vygenerovaného kódu.

Při zvažování, kterou možnost použít, mějte na paměti, že existuje kompromis mezi počtem požadavků na databázi a množstvím dat vrácených v jednom dotazu. Další informace naleznete v tématu Načítání souvisejících objektů.

Použití cest dotazů

Cesty dotazu definují graf objektů, které dotaz vrací. Při definování cesty dotazu se k vrácení všech objektů, které cesta definuje, vyžaduje pouze jeden požadavek na databázi. Použití cest dotazů může vést ke spouštění složitých příkazů vůči zdroji dat z zdánlivě jednoduchých dotazů na objekty. K tomu dochází, protože jedno nebo více spojení je nutné k vrácení souvisejících objektů v jednom dotazu. Tato složitost je větší v dotazech na komplexní model entit, jako je například entita s dědičností nebo cesta, která zahrnuje relace M:N.

Poznámka:

ToTraceString Pomocí metody zobrazíte příkaz, který bude generován pomocí ObjectQuery<T>. Další informace naleznete v tématu Postupy: Zobrazení příkazů úložiště.

Pokud cesta dotazu obsahuje příliš mnoho souvisejících objektů nebo objekty obsahují příliš mnoho dat řádků, zdroj dat nemusí dotaz dokončit. K tomu dochází v případě, že dotaz vyžaduje dočasné úložiště, které překračuje možnosti zdroje dat. V takovém případě můžete snížit složitost dotazu zdroje dat explicitním načtením souvisejících objektů.

Související objekty můžete explicitně načíst voláním Load metody na navigační vlastnosti, která vrací nebo EntityCollection<TEntity> EntityReference<TEntity>. Explicitní načítání objektů vyžaduje odezvu do databáze při každém Load zavolání.

Poznámka:

Pokud voláte Load smyčku v kolekci vrácených objektů, například při použití foreach příkazu (For Each v jazyce Visual Basic), musí poskytovatel konkrétního zdroje dat podporovat více aktivních sad výsledků v jednom připojení. Pro databázi SYSTÉMU SQL Server je nutné zadat hodnotu MultipleActiveResultSets = true v připojovací řetězec zprostředkovatele.

Metodu LoadProperty můžete použít také v případě, že entity neobsahují žádné EntityCollection<TEntity> vlastnosti nebo EntityReference<TEntity> vlastnosti. To je užitečné při používání entit POCO.

I když explicitní načítání souvisejících objektů sníží počet spojení a sníží množství redundantních dat, Load vyžaduje opakované připojení k databázi, což může být nákladné při explicitním načítání velkého počtu objektů.

Ukládání změn

Při volání SaveChanges metody na ObjectContext, samostatné vytvoření, aktualizace nebo odstranění příkaz se vygeneruje pro každý přidaný, aktualizovaný nebo odstraněný objekt v kontextu. Tyto příkazy se spouští ve zdroji dat v jedné transakci. Stejně jako u dotazů závisí výkon operací vytvoření, aktualizace a odstranění na složitosti mapování v koncepčním modelu.

Distribuované transakce

Operace v explicitní transakci, která vyžaduje prostředky spravované koordinátorem distribuovaných transakcí (DTC), budou mnohem dražší než podobná operace, která nevyžaduje DTC. Povýšení do DTC bude probíhat v následujících situacích:

  • Explicitní transakce s operací proti databázi SQL Serveru 2000 nebo jinému zdroji dat, které vždy propagují explicitní transakce do DTC.

  • Explicitní transakce s operací s SQL Serverem 2005, pokud je připojení spravováno rozhraním Entity Framework. K tomu dochází, protože SQL Server 2005 podporuje DTC při každém zavření a opětovném otevření připojení v rámci jedné transakce, což je výchozí chování Entity Framework. K této povýšení DTC nedojde při použití SQL Serveru 2008. Chcete-li zabránit této povýšení při použití SQL Server 2005, musíte explicitně otevřít a zavřít připojení v rámci transakce. Další informace naleznete v tématu Správa Připojení ionů a transakcí.

Explicitní transakce se používá při provádění jedné nebo více operací uvnitř System.Transactions transakce. Další informace naleznete v tématu Správa Připojení ionů a transakcí.

Strategie pro zlepšení výkonu

Celkový výkon dotazů v Entity Frameworku můžete zlepšit pomocí následujících strategií.

Předgenerování zobrazení

Generování zobrazení na základě modelu entity je významné náklady při prvním spuštění dotazu aplikací. Pomocí nástroje EdmGen.exe můžete předem vygenerovat zobrazení jako soubor kódu jazyka Visual Basic nebo C#, který lze přidat do projektu během návrhu. K vygenerování předem zkompilovaných zobrazení můžete použít také sadu nástrojů pro transformaci textových šablon. Předgenerovaná zobrazení se ověřují za běhu, aby se zajistilo, že jsou konzistentní s aktuální verzí zadaného modelu entity. Další informace naleznete v tématu Postupy: Předgenerování zobrazení za účelem zlepšení výkonu dotazů.

Při práci s velmi velkými modely platí následující aspekty:

Formát metadat .NET omezuje počet znaků uživatelského řetězce v daném binárním souboru na 16 777 215 (0xFFFFFF). Pokud generujete zobrazení pro velmi velký model a soubor zobrazení dosáhne tohoto limitu velikosti, zobrazí se chyba kompilace Bez logického prostoru pro vytvoření více uživatelských řetězců. Toto omezení velikosti platí pro všechny spravované binární soubory. Další informace najdete v blogu , který ukazuje, jak se vyhnout chybě při práci s velkými a složitými modely.

Zvažte použití možnosti sloučení NoTracking pro dotazy.

Ke sledování vrácených objektů v kontextu objektu se vyžadují náklady. Detekce změn objektů a zajištění toho, aby více požadavků na stejnou logickou entitu vrátilo stejnou instanci objektu, vyžaduje připojení objektů k ObjectContext instanci. Pokud neplánujete provádět aktualizace nebo odstranění objektů a nevyžadujete správu identit, zvažte použití NoTracking možností sloučení při provádění dotazů.

Vrácení správného množství dat

V některýchscénářch Include V jiných scénářích ale může být další doba odezvy databáze za účelem načtení souvisejících objektů rychlejší, protože jednodušší dotazy s menším počtem spojení vedou k menší redundanci dat. Z tohoto důvodu doporučujeme otestovat výkon různých způsobů načítání souvisejících objektů. Další informace naleznete v tématu Načítání souvisejících objektů.

Pokud se chcete vyhnout vrácení příliš velkého množství dat v jednom dotazu, zvažte stránkování výsledků dotazu do lépe spravovatelných skupin. Další informace naleznete v tématu Postupy: Page Through Query Results.

Omezení rozsahu ObjectContext

Ve většině případů byste měli vytvořit ObjectContext instanci v příkazu using (Using…End Using v jazyce Visual Basic). To může zvýšit výkon tím, že zajistí, aby prostředky přidružené k kontextu objektu byly uvolněny automaticky, když kód ukončí blok příkazu. Pokud jsou však ovládací prvky svázané s objekty spravovanými kontextem objektu, ObjectContext měla by být instance zachována, pokud je nutná vazba a odstraněna ručně. Další informace naleznete v tématu Správa Připojení ionů a transakcí.

Zvažte ruční otevření připojení k databázi.

Když vaše aplikace provádí řadu dotazů na objekt nebo často volá SaveChanges operace vytváření, aktualizace a odstranění ve zdroji dat, musí Entity Framework nepřetržitě otevírat a zavírat připojení ke zdroji dat. V těchto situacích zvažte ruční otevření připojení na začátku těchto operací a zavření nebo odstranění připojení po dokončení operací. Další informace naleznete v tématu Správa Připojení ionů a transakcí.

Výkonnostní data

Některá data o výkonu pro Entity Framework jsou publikována v následujících příspěvcích na blogu týmu ADO.NET:

Viz také