Modelování pro výkon

V mnohapřípadechch zatímco správně normalizovaný a "správný" model je obvykle dobrým výchozím bodem, v aplikacích z reálného světa mohou některé pragmatičtější kompromisy trvat dlouhou cestu k dosažení dobrého výkonu. Vzhledem k tomu, že je poměrně obtížné změnit model, jakmile aplikace běží v produkčním prostředí, je vhodné při vytváření počátečního modelu mít na paměti výkon.

Denormalizace a ukládání do mezipaměti

Denormalizace je postup přidání redundantních dat do schématu, obvykle kvůli odstranění spojení při dotazování. Například pro model s blogy a příspěvky, kde každý příspěvek má hodnocení, může být nutné, abyste často zobrazovali průměrné hodnocení blogu. Jednoduchý přístup k tomu by seskupil příspěvky podle svého blogu a vypočítal průměr jako součást dotazu; ale to vyžaduje nákladné spojení mezi těmito dvěma tabulkami. Denormalizace by přidala počítaný průměr všech příspěvků do nového sloupce na blogu, aby byl okamžitě přístupný bez spojení nebo výpočtu.

Výše uvedené informace lze zobrazit jako formu ukládání do mezipaměti – agregované informace z příspěvků se ukládají do mezipaměti na svém blogu. Stejně jako u ukládání do mezipaměti je problém, jak zachovat hodnotu uloženou v mezipaměti aktuální s daty, která se ukládají do mezipaměti. V mnoha případech je v pořádku, aby se data uložená v mezipaměti trochu zpožďovala; Například ve výše uvedeném příkladu je obvykle rozumné, aby průměrné hodnocení blogu nebylo v žádném daném bodě úplně aktuální. Pokud to tak je, můžete ho nechat přepočítat vždy a potom; jinak musí být propracovanější systém nastavený tak, aby hodnoty uložené v mezipaměti byly aktuální.

Následující část podrobně popisuje některé techniky denormalizace a ukládání do mezipaměti v EF Core a odkazuje na příslušné části v dokumentaci.

Uložené počítané sloupce

Pokud jsou data uložená v mezipaměti produktem jiných sloupců ve stejné tabulce, může být uložený počítaný sloupec dokonalým řešením. Může například Customer obsahovat FirstName a LastName sloupce, ale možná budeme muset hledat podle celého jména zákazníka. Uložený počítaný sloupec se automaticky udržuje v databázi, která ji přepočítá pokaždé, když se řádek změní, a můžete dokonce definovat index, aby se urychlily dotazy.

Aktualizace sloupců mezipaměti při změně vstupů

Pokud sloupec uložený v mezipaměti potřebuje odkazovat na vstupy mimo řádek tabulky, nemůžete použít počítané sloupce. Přesto je však možné přepočítat sloupec vždy, když se změní jeho vstup; Můžete například přepočítat průměrné hodnocení blogu při každé změně, přidání nebo odebrání příspěvku. Nezapomeňte určit přesné podmínky, kdy je potřeba přepočítat, jinak se hodnota uložená v mezipaměti nesynchronizuje.

Jedním ze způsobů, jak to udělat, je provést aktualizaci sami prostřednictvím běžného rozhraní EF Core API. SaveChangesUdálosti nebo průsečíky lze použít k automatické kontrole, jestli se nějaké příspěvky aktualizují, a k provedení přepočtu tímto způsobem. Všimněte si, že to obvykle zahrnuje další zaokrouhlení databáze, protože je potřeba odeslat další příkazy.

U více aplikací citlivých na výkon je možné definovat triggery databáze, které automaticky provádějí přepočet v databázi. Tím se uloží dodatečné zaokrouhlování databáze, automaticky proběhne ve stejné transakci jako hlavní aktualizace a může být jednodušší nastavit. EF neposkytuje žádné konkrétní rozhraní API pro vytváření nebo údržbu triggerů, ale je naprosto v pořádku vytvořit prázdnou migraci a přidat definici triggeru prostřednictvím nezpracovaného SQL.

Materializovaná nebo indexovaná zobrazení

Materializovaná (nebo indexovaná) zobrazení se podobají běžným zobrazením s tím rozdílem, že jejich data jsou uložená na disku (materializovaná), a ne při každém dotazování zobrazení. Taková zobrazení jsou koncepčně podobná uloženým vypočítaným sloupcům, protože ukládají výsledky potenciálně drahých výpočtů do mezipaměti; Ale ukládají do mezipaměti celou sadu výsledků dotazu místo jednoho sloupce. Materializovaná zobrazení se dají dotazovat stejně jako jakákoli běžná tabulka a protože jsou uložená v mezipaměti na disku, tyto dotazy se spouštějí velmi rychle a levně, aniž by musely neustále provádět nákladné výpočty dotazu, které definují zobrazení.

Konkrétní podpora materializovaných zobrazení se v různých databázích liší. V některých databázích (např. PostgreSQL) musí být materializovaná zobrazení aktualizována ručně, aby se jejich hodnoty synchronizovaly s podkladovými tabulkami. Obvykle se to provádí prostřednictvím časovače – v případech, kdy je přijatelná prodleva dat – nebo voláním triggeru nebo uložené procedury v určitých podmínkách. Indexovaná zobrazení SQL Serveru se na druhou stranu automaticky aktualizují při úpravě jejich podkladových tabulek. Tím zajistíte, že zobrazení bude vždy zobrazovat nejnovější data za cenu pomalejších aktualizací. Kromě toho zobrazení indexu SQL Serveru mají různá omezení týkající se toho, co podporují; další informace najdete v dokumentaci .

EF v současné době neposkytuje žádné konkrétní rozhraní API pro vytváření nebo údržbu zobrazení, materializované nebo indexované nebo jinak; ale je naprosto v pořádku vytvořit prázdnou migraci a přidat definici zobrazení prostřednictvím nezpracovaného SQL.

Mapování dědičnosti

Než budete pokračovat v této části, doporučujeme přečíst si vyhrazenou stránku o dědičnosti .

EF Core v současné době podporuje tři techniky mapování modelu dědičnosti na relační databázi:

  • Tabulka na hierarchii (TPH), ve které je namapovaná celá hierarchie tříd .NET na jednoúčelovou tabulku databáze.
  • Tabulka podle typu (TPT), ve které je každý typ v hierarchii .NET mapován na jinou tabulku v databázi.
  • Typ TPC (Table-per-beton-type ), ve kterém je každý konkrétní typ v hierarchii .NET mapován na jinou tabulku v databázi, kde každá tabulka obsahuje sloupce pro všechny vlastnosti odpovídajícího typu.

Volba techniky mapování dědičnosti může mít značný dopad na výkon aplikace – doporučuje se pečlivě měřit před potvrzením výběru.

Intuitivně se TPT může zdát jako "čistější" technika; Samostatná tabulka pro každý typ .NET způsobí, že schéma databáze bude vypadat podobně jako hierarchie typů .NET. Kromě toho, protože TPH musí představovat celou hierarchii v jedné tabulce, řádky mají všechny sloupce bez ohledu na typ, který se ve skutečnosti uchovává v řádku, a nesouvisející sloupce jsou vždy prázdné a nepoužité. Kromě toho, že se zdá, že je "nečistá" technika mapování, mnozí věří, že tyto prázdné sloupce zabírají značné místo v databázi a mohou také poškodit výkon.

Tip

Pokud váš databázový systém podporuje (např. SQL Server), zvažte použití "řídkých sloupců" pro sloupce TPH, které budou zřídka vyplněny.

Měření však ukazuje, že TPT je ve většině případů nižší technikou mapování z hlediska výkonu; kde všechna data v TPH pocházejí z jedné tabulky, musí dotazy TPT spojit více tabulek a spojení jsou jedním z primárních zdrojů problémů s výkonem v relačních databázích. Databáze také obvykle dobře pracují s prázdnými sloupci a funkce, jako jsou řídké sloupce SQL Serveru, můžou tuto režii ještě více snížit.

TPC má podobné charakteristiky výkonu jako TPH, ale při výběru entit všech typů je o něco pomalejší, protože to zahrnuje několik tabulek. TPC ale ve skutečnosti vyniká při dotazování entit jednoho typu list – dotaz používá jenom jednu tabulku a nepotřebuje žádné filtrování.

Konkrétní příklad najdete v tomto srovnávacím testu, který nastaví jednoduchý model s hierarchií 7 typů. Pro každý typ se zasadí 5 000 řádků – celkem 35 000 řádků – a srovnávací test jednoduše načte všechny řádky z databáze:

Metoda Střední hodnota Chyba Směrodatná odchylka Gen 0 Gen 1 Přiděleno
TPH 149.0 ms 3.38 ms 9.80 ms 4000.0000 1000.0000 40 MB
TPT 312.9 ms 6.17 ms 10.81 ms 9000.0000 3000.0000 75 MB
TPC 158.2 ms 3.24 ms 8.88 ms 5000.0000 2000.0000 46 MB

Jak je vidět, TPH a TPC jsou pro tento scénář výrazně efektivnější než TPT. Mějte na paměti, že skutečné výsledky vždy závisejí na konkrétním dotazu, který se spouští, a počtu tabulek v hierarchii, takže ostatní dotazy můžou ukázat jiný rozdíl v výkonu; Doporučujeme použít tento srovnávací kód jako šablonu pro testování jiných dotazů.