Přítel nebo nepřítel? Pohledy na SQL Server byly předmětem vášnivých debat, když jsem byl v prvním roce používání SQL Serveru. Říkali, že je to špatné, protože je to pomalé. Ale co dnes?
Jste na stejné lodi jako já před mnoha lety? Pak se ke mně připojte na této cestě, abyste odhalili skutečnou dohodu o zobrazeních SQL, abyste je mohli napsat co nejrychleji.
SQL pohledy jsou virtuální tabulky. Záznamy v pohledu jsou výsledkem dotazu v něm. Kdykoli se aktualizují základní tabulky použité v pohledu, aktualizuje se také pohled. V některých případech můžete také záznamy VLOŽIT, AKTUALIZOVAT a SMAZAT v zobrazení jako tabulku. I když jsem to sám nezkoušel.
Podobně jako u tabulky můžete pohled VYTVOŘIT, ZMĚNIT nebo ZRUŠIT. S určitými omezeními můžete dokonce vytvořit index.
Všimněte si, že jsem ve vzorových kódech použil SQL Server 2019.
1. Poznejte správné a nesprávné použití SQL View
Nejprve základy.
K čemu jsou SQL pohledy?
Je to zásadní. Pokud jej používáte jako kladivo do šroubováku, zapomeňte na rychlejší SQL pohledy. Nejprve si připomeňme správné použití:
- Zaměření, zjednodušení a přizpůsobení vnímání databáze každým uživatelem.
- Umožnit uživatelům přístup k jediným informacím, které z bezpečnostních důvodů potřebují vidět.
- Zajistit zpětnou kompatibilitu se starou tabulkou nebo starým schématem, aby nedošlo k přerušení závislých aplikací. Je to dočasné, dokud nebudou dokončeny všechny potřebné změny.
- Rozdělit data pocházející z různých serverů. Proto se jeví, jako by se jednalo o jednu tabulku z jednoho serveru nebo instance.
Jak NEPOUŽÍVAT zobrazení SQL Server?
- Znovu použijte zobrazení v jiném zobrazení, které bude znovu použito v dalším, jiném zobrazení. Zkrátka hluboce vnořené pohledy. Opětovné použití kódu má v tomto případě několik nevýhod.
- Ušetřete na stisknutí kláves. Vztahuje se k prvnímu, který snižuje tlak prstů a zdá se, že urychluje kódování.
Pokud je nesprávné použití pohledů povoleno, zakryje skutečný důvod, proč pohledy vytváříte. Jak uvidíte později, skutečné výhody převažují nad vnímanými výhodami nesprávného použití.
Příklad
Podívejme se na příklad od společnosti Microsoft. vEmployee zobrazit z AdventureWorks . Zde je kód:
-- Employee names and basic contact information
CREATE VIEW [HumanResources].[vEmployee]
AS
SELECT
e.[BusinessEntityID]
,p.[Title]
,p.[FirstName]
,p.[MiddleName]
,p.[LastName]
,p.[Suffix]
,e.[JobTitle]
,pp.[PhoneNumber]
,pnt.[Name] AS [PhoneNumberType]
,ea.[EmailAddress]
,p.[EmailPromotion]
,a.[AddressLine1]
,a.[AddressLine2]
,a.[City]
,sp.[Name] AS [StateProvinceName]
,a.[PostalCode]
,cr.[Name] AS [CountryRegionName]
,p.[AdditionalContactInfo]
FROM [HumanResources].[Employee] e
INNER JOIN [Person].[Person] p
ON p.[BusinessEntityID] = e.[BusinessEntityID]
INNER JOIN [Person].[BusinessEntityAddress] bea
ON bea.[BusinessEntityID] = e.[BusinessEntityID]
INNER JOIN [Person].[Address] a
ON a.[AddressID] = bea.[AddressID]
INNER JOIN [Person].[StateProvince] sp
ON sp.[StateProvinceID] = a.[StateProvinceID]
INNER JOIN [Person].[CountryRegion] cr
ON cr.[CountryRegionCode] = sp.[CountryRegionCode]
LEFT OUTER JOIN [Person].[PersonPhone] pp
ON pp.BusinessEntityID = p.[BusinessEntityID]
LEFT OUTER JOIN [Person].[PhoneNumberType] pnt
ON pp.[PhoneNumberTypeID] = pnt.[PhoneNumberTypeID]
LEFT OUTER JOIN [Person].[EmailAddress] ea
ON p.[BusinessEntityID] = ea.[BusinessEntityID];
GO
Účel tohoto pohledu se zaměřuje na základní informace o zaměstnanci. Pokud to personál lidských zdrojů potřebuje, může být zobrazen na webové stránce. Byl znovu použit v jiných zobrazeních?
Zkuste toto:
- V SQL Server Management Studio , vyhledejte AdventureWorks databáze.
- Rozbalte složku Zobrazení a vyhledejte [HumanResources].[vEmployee].
- Klikněte na něj pravým tlačítkem a vyberte možnost Zobrazit závislosti .
Pokud vidíte jiný pohled závislý na tomto pohledu, který pak závisí na jiném pohledu, Microsoft nám dal špatný příklad. Pak ale neexistují žádné další závislosti zobrazení.
Pojďme na další.
2. Odhalte mýtus o SQL View
Když SQL Server zpracuje SELECT ze zobrazení , vyhodnotí kód v pohledu PŘED tím, než se bude zabývat klauzulí WHERE nebo jakýmkoli spojením ve vnějším dotazu. S více připojenými tabulkami to bude pomalé ve srovnání s SELECT ze základních tabulek se stejnými výsledky.
Alespoň mi to bylo řečeno, když jsem začal používat SQL. Ať už je to mýtus nebo ne, existuje jen jeden způsob, jak to zjistit. Pojďme k praktickému příkladu.
Jak fungují zobrazení SQL
Microsoft nás nenechal ve tmě nekonečně debatovat. Máme nástroje k tomu, abychom viděli, jak dotazy fungují, jako je STATISTICS IO a Plán skutečného provádění . Budeme je používat ve všech našich příkladech. Pojďme si dát první.
USE AdventureWorks
GO
SELECT * FROM HumanResources.vEmployee e
WHERE e.BusinessEntityID = 105
Chcete-li zjistit, co se děje, když SQL Server zpracovává pohled, prohlédněte si Plán skutečného provedení na obrázku 1. Porovnáme jej s kódem CREATE VIEW pro vEmployee v předchozí části.
Jak můžete vidět, první uzly zpracované SQL Serverem jsou ty, které používají INNER JOIN. Poté pokračuje ve zpracování LEFT OUTER JOINs.
Protože nikde nevidíme uzel Filter pro klauzuli WHERE, musí být v jednom z těchto uzlů. Pokud zkontrolujete vlastnosti všech uzlů, uvidíte zpracovanou klauzuli WHERE v tabulce Zaměstnanec. Uzavřel jsem jej do rámečku na obrázku 1. Chcete-li dokázat, že tam je, podívejte se na obrázek 2, kde jsou vlastnosti tohoto uzlu:
Analýza
Takže měl příkaz SELECT v vEmployee pohled byl vyhodnocen nebo zpracován PŘED uplatněním klauzule WHERE? Prováděcí plán ukazuje, že ne. Pokud byl, měl by se objevit nejblíže uzlu SELECT.
To, co mi bylo řečeno, byl mýtus. Vyhýbal jsem se něčemu dobrému kvůli nepochopení správného použití zobrazení SQL.
Nyní, když víme, jak SQL Server zpracovává SELECT z pohledu , otázkou zůstává:Je to pomalejší než nepoužívat pohled?
SELECT FROM View vs. SELECT FROM Base Tables – který z nich poběží rychleji?
Nejprve musíme extrahovat příkaz SELECT uvnitř vEmployee zobrazit a vytvořit stejný výsledek, jaký jsme měli při použití pohledu. Níže uvedený kód zobrazuje stejnou klauzuli WHERE:
USE AdventureWorks
GO
-- SELECT FROM a view
SELECT * FROM HumanResources.vEmployee e
WHERE e.BusinessEntityID = 105
-- SELECT FROM Base Tables
SELECT
e.[BusinessEntityID]
,p.[Title]
,p.[FirstName]
,p.[MiddleName]
,p.[LastName]
,p.[Suffix]
,e.[JobTitle]
,pp.[PhoneNumber]
,pnt.[Name] AS [PhoneNumberType]
,ea.[EmailAddress]
,p.[EmailPromotion]
,a.[AddressLine1]
,a.[AddressLine2]
,a.[City]
,sp.[Name] AS [StateProvinceName]
,a.[PostalCode]
,cr.[Name] AS [CountryRegionName]
,p.[AdditionalContactInfo]
FROM [HumanResources].[Employee] e
INNER JOIN [Person].[Person] p
ON p.[BusinessEntityID] = e.[BusinessEntityID]
INNER JOIN [Person].[BusinessEntityAddress] bea
ON bea.[BusinessEntityID] = e.[BusinessEntityID]
INNER JOIN [Person].[Address] a
ON a.[AddressID] = bea.[AddressID]
INNER JOIN [Person].[StateProvince] sp
ON sp.[StateProvinceID] = a.[StateProvinceID]
INNER JOIN [Person].[CountryRegion] cr
ON cr.[CountryRegionCode] = sp.[CountryRegionCode]
LEFT OUTER JOIN [Person].[PersonPhone] pp
ON pp.BusinessEntityID = p.[BusinessEntityID]
LEFT OUTER JOIN [Person].[PhoneNumberType] pnt
ON pp.[PhoneNumberTypeID] = pnt.[PhoneNumberTypeID]
LEFT OUTER JOIN [Person].[EmailAddress] ea
ON p.[BusinessEntityID] = ea.[BusinessEntityID]
WHERE e.BusinessEntityID = 105
Poté zkontrolujeme STATISTICS IO a provedeme Porovnání plánu zobrazení . Kolik zdrojů bude potřebovat dotaz z pohledu ve srovnání s dotazováním ze základních tabulek? Viz obrázek 3.
Zde bude dotazování z pohledu nebo základních tabulek spotřebovávat stejné logické čtení. Oba použili stránky o velikosti 19 * 8 kB. Na základě toho je to nerozhodné, kdo je rychlejší. Jinými slovy, použití pohledu nezhorší výkon. Porovnejme Plán skutečného provedení obou pomocí Porovnat plán zobrazení :
Vidíte stínovanou část diagramu? Co třeba QueryPlanHash oba? Protože oba dotazy mají stejnou hodnotu QueryPlanHash a stejné operace, zobrazení nebo základní tabulky bude SQL Server zpracovány stejně .
Stejná logická čtení a stejný plán vzorku nám říkají, že oba budou fungovat stejně. Vysoké logické čtení tedy způsobí, že váš dotaz bude probíhat pomalu, ať už používáte pohledy nebo ne. Znalost této skutečnosti vám pomůže problém vyřešit a urychlí zobrazení.
Bohužel jsou tu špatné zprávy.
Připojování pohledů SQL k tabulkám
To, co jste viděli dříve, je SELECT z pohledu bez spojení. Co když však připojíte stůl k pohledu?
Podívejme se na další příklad. Tentokrát používáme vSalesPerson zobrazit v AdventureWorks – seznam prodejců s kontaktními informacemi a prodejní kvótou. Opět porovnáme příkaz s SELECT ze základních tabulek:
-- get the total sales orders for each salesperson
-- using the view joined with SalesOrderHeader
SELECT
sp.FirstName
,sp.MiddleName
,sp.LastName
,SUM(soh.TotalDue) AS TotalSalesOrders
FROM Sales.vSalesPerson sp
INNER JOIN Sales.SalesOrderHeader soh ON sp.BusinessEntityID = soh.SalesPersonID
GROUP BY sp.LastName, sp.MiddleName, sp.FirstName
-- using base tables
SELECT
p.FirstName
,p.MiddleName
,p.LastName
,SUM(soh.TotalDue) AS TotalSalesOrders
FROM sales.SalesPerson sp
INNER JOIN Person.Person p ON sp.BusinessEntityID = P.BusinessEntityID
INNER JOIN Sales.SalesOrderHeader soh ON sp.BusinessEntityID = soh.SalesPersonID
GROUP BY p.LastName, p.MiddleName, p.FirstName
Pokud si myslíte, že to bude také stejné, zkontrolujte STATISTICS IO:
Překvapený? Připojení k vSalesPerson zobrazit pomocí SalesOrderHeader tabulka potřebuje obrovské zdroje (28 240 x 8 kB) ve srovnání s pouhým použitím základních tabulek (774 x 8 kB). Všimněte si také, že obsahuje některé tabulky, které jsme nepotřebovali (tabulky v červených rámečcích). Natož vyšší logické čtení na SalesOrderHeader při použití zobrazení.
Tím to ale nekončí.
Skutečný plán provádění odhaluje více
Všimněte si skutečného plánu provádění dotazu na základní tabulky:
Zdá se, že obrázek ukazuje docela normální plán provádění. Ale podívejte se na ten s pohledem:
Plán provádění na obrázku 7 se shoduje se STATISTICS IO na obrázku 5. Z pohledu vidíme tabulky, které nepotřebujeme. K dispozici je také Vyhledání klíčů uzel s odhadem řádku, který je o více než tisíc záznamů mimo skutečné řádky. Nakonec se také objeví varování v uzlu SELECT. Co by to mohlo být?
Co je to ExcessiveGrant varování v uzlu SELECT?
K nadměrnému udělení dojde, když je maximální využitá paměť příliš malá ve srovnání s přidělenou pamětí. V tomto případě bylo přiděleno 1024 kB, ale bylo použito pouze 16 kB.
Memory Grant je odhadované množství paměti v KB potřebné ke spuštění plánu.
Může se jednat o nesprávné odhady ve Vyhledávání klíčů uzel a/nebo zahrnutí tabulek, které jsme nepotřebovali, do plánu, který to způsobil. Také příliš mnoho přidělené paměti může způsobit zablokování. Zbývajících 1008 kB mohlo být užitečných pro jiné operace.
Nakonec se něco pokazilo, když jste pohled spojili se stolem. Pokud se dotazujeme ze základních tabulek, nemusíme tyto problémy řešit.
Takové věci
Bylo to dlouhé vysvětlování. Víme však, že pohledy se nevyhodnocují ani nezpracovávají PŘED vyhodnocením klauzule WHERE nebo spojení ve vnějším dotazu. Také jsme dokázali, že oba budou fungovat stejně.
Na druhou stranu existuje případ, kdy připojíme pohled ke stolu. Využívá spojení tabulek, které z pohledu nepotřebujeme. Jsou pro nás neviditelné, pokud nezkontrolujeme STATISTICS IO a Skutečný plán provádění. To vše může poškodit výkon a problémy se mohou objevit z ničeho.
Proto:
- Měli bychom vědět, jak dotazy, včetně zobrazení, fungují zevnitř.
- STATISTICS IO a Actual Execution Plans odhalí, jak budou fungovat dotazy a zobrazení.
- Nemůžeme pouze připojit pohled k tabulce a znovu jej bezstarostně použít. Vždy zkontrolujte STATISTICS IO a skutečné plány provádění! Místo opětovného používání pohledů a jejich vnořování pro „vylepšenou“ produktivitu kódování používám IntelliSense a nástroj pro dokončování kódu, jako je SQL Complete.
Pak si můžeme být jisti, že nenapíšeme pohledy, které budou mít správné výsledky, ale poběží jako šnek.
3. Vyzkoušejte indexovaná zobrazení
Indexovaná zobrazení jsou to, co název napovídá. Může zvýšit výkon příkazů SELECT. Ale stejně jako indexy tabulek může mít vliv na výkon, pokud jsou základní tabulky velké a průběžně aktualizované.
Chcete-li zjistit, jak mohou indexovaná zobrazení zlepšit výkon dotazů, prozkoumejte vStateProvinceCountryRegion zobrazit v AdventureWorks . Zobrazení je indexováno na StateProvinceID a CountryRegionCode . Jedná se o seskupený jedinečný index.
Porovnejme STATISTICS IO pohledu, který nemá index a má index. Díky tomu zjistíme, kolik stránek o velikosti 8 kB přečte náš SQL Server:
Obrázek ukazuje, že mít index v vStateProvinceCountryRegion view redukuje logické čtení na polovinu. Je to 50% zlepšení ve srovnání s tím, že nemáte index.
To rád slyším.
Přesto znovu nepřidávejte indexy do svých pohledů nedbale. Kromě dlouhého seznamu přísných pravidel pro 1 jedinečný seskupený index to může zhoršit výkon, podobně jako urychlené přidávání indexů do tabulek. Zkontrolujte také STATISTICS IO, pokud po přidání indexu došlo k poklesu logických čtení.
Takové věci
Jak jsme viděli v našem příkladu, indexovaná zobrazení mohou zlepšit výkon zobrazení SQL.
BONUSOVÝ TIP
Stejně jako jakýkoli jiný dotaz poběží zobrazení SQL rychle, pokud:
- Statistiky jsou aktualizovány
- Byly přidány chybějící indexy
- Indexy jsou defragmentovány
- Indexy používají správný FILLFACTOR
Závěr
Jsou pohledy SQL dobré nebo špatné?
SQL pohledy jsou dobré, pokud je napíšeme správně a zkontrolujeme, jak budou zpracovány. Máme nástroje jako STATISTICS IO a Actual Execution Plan – používejte je! Indexovaná zobrazení mohou také zlepšit výkon.
Líbí se vám tento příspěvek? Sdílejte prosím lásku na své oblíbené platformě sociálních médií.